public static ComputerProp GetComputerProps(SearchResultEntry entry, ResolvedEntry resolved)
        {
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled = (flags & UacFlags.AccountDisable) == 0;
            }
            else
            {
                enabled = true;
            }
            var lastLogon = ConvertToUnixEpoch(entry.GetProp("lastlogon"));
            var lastSet   = ConvertToUnixEpoch(entry.GetProp("pwdlastset"));
            var sid       = entry.GetSid();
            var os        = entry.GetProp("operatingsystem");
            var sp        = entry.GetProp("operatingsystemservicepack");

            if (sp != null)
            {
                os = $"{os} {sp}";
            }

            return(new ComputerProp
            {
                ComputerName = resolved.BloodHoundDisplay,
                Enabled = enabled,
                LastLogon = lastLogon,
                ObjectSid = sid,
                OperatingSystem = os,
                PwdLastSet = lastSet
            });
        }
예제 #2
0
        public static string ResolveBloodhoundDisplay(this SearchResultEntry result)
        {
            var accountName       = result.GetProp("samaccountname");
            var distinguishedName = result.DistinguishedName;
            var accountType       = result.GetProp("samaccounttype");

            //I have no idea if this is a thing
            if (distinguishedName == null)
            {
                return(null);
            }

            var domain = Utils.ConvertDnToDomain(distinguishedName);

            if (Groups.Contains(accountType) || Users.Contains(accountType))
            {
                return($"{accountName.ToUpper()}@{domain}");
            }

            if (Computers.Contains(accountType))
            {
                var dnsHostName = result.GetProp("dnshostname") ?? $"{accountName.TrimEnd('$')}.{domain}";

                return(dnsHostName.ToUpper());
            }

            //If we got here, we have a domain ACL object
            return(Utils.ConvertDnToDomain(distinguishedName));
        }
예제 #3
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref Gpo obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }

            obj.Properties.Add("description", entry.GetProp("description"));
            obj.Properties.Add("gpcpath", entry.GetProp("gpcfilesyspath"));
        }
예제 #4
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref Domain obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }

            obj.Properties.Add("description", entry.GetProp("description"));
            if (!int.TryParse(entry.GetProp("msds-behavior-version"), out var level))
            {
                level = -1;
            }
            string func;

            switch (level)
            {
            case 0:
                func = "2000 Mixed/Native";
                break;

            case 1:
                func = "2003 Interim";
                break;

            case 2:
                func = "2003";
                break;

            case 3:
                func = "2008";
                break;

            case 4:
                func = "2008 R2";
                break;

            case 5:
                func = "2012";
                break;

            case 6:
                func = "2012 R2";
                break;

            case 7:
                func = "2016";
                break;

            default:
                func = "Unknown";
                break;
            }

            obj.Properties.Add("functionallevel", func);
        }
예제 #5
0
        public static string GetObjectType(this SearchResultEntry result)
        {
            var accountType = result.GetProp("samaccounttype");

            if (Groups.Contains(accountType))
            {
                return("group");
            }

            if (Users.Contains(accountType))
            {
                return("user");
            }

            if (Computers.Contains(accountType))
            {
                return("computer");
            }

            if (TrustAccount.Contains(accountType))
            {
                return("trustaccount");
            }

            if (result.DistinguishedName.Contains("ForeignSecurityPrincipals"))
            {
                return("foreignsecurityprincipal");
            }

            return("domain");
        }
예제 #6
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref Computer obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled, unconstrained, trustedToAuth;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled       = (flags & UacFlags.AccountDisable) == 0;
                unconstrained = (flags & UacFlags.TrustedForDelegation) == UacFlags.TrustedForDelegation;
                trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0;
            }
            else
            {
                unconstrained = false;
                enabled       = true;
                trustedToAuth = false;
            }

            var comps = new List <string>();

            if (trustedToAuth)
            {
                var delegates = entry.GetPropArray("msds-allowedToDelegateTo");
                obj.Properties.Add("allowedtodelegate", delegates);

                foreach (var d in delegates)
                {
                    var hname = d.Contains("/") ? d.Split('/')[1] : d;
                    hname = hname.Split(':')[0];
                    var resolvedHost = Utils.Instance.ResolveHost(hname);
                    if (resolvedHost.Contains("."))
                    {
                        comps.Add(resolvedHost.ToUpper());
                    }
                }
            }
            obj.AllowedToDelegate = comps.Distinct().ToArray();

            obj.Properties.Add("enabled", enabled);
            obj.Properties.Add("unconstraineddelegation", unconstrained);
            obj.Properties.Add("lastlogon", ConvertToUnixEpoch(entry.GetProp("lastlogon")));
            obj.Properties.Add("lastlogontimestamp", ConvertToUnixEpoch(entry.GetProp("lastlogontimestamp")));
            obj.Properties.Add("pwdlastset", ConvertToUnixEpoch(entry.GetProp("pwdlastset")));
            obj.Properties.Add("serviceprincipalnames", entry.GetPropArray("serviceprincipalname"));
            var os = entry.GetProp("operatingsystem");
            var sp = entry.GetProp("operatingsystemservicepack");

            if (sp != null)
            {
                os = $"{os} {sp}";
            }

            obj.Properties.Add("operatingsystem", os);
            obj.Properties.Add("description", entry.GetProp("description"));
        }
예제 #7
0
        public static ComputerProp GetComputerProps(SearchResultEntry entry, ResolvedEntry resolved)
        {
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled;
            bool unconstrained;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled       = (flags & UacFlags.AccountDisable) == 0;
                unconstrained = (flags & UacFlags.TrustedForDelegation) == UacFlags.TrustedForDelegation;
            }
            else
            {
                unconstrained = false;
                enabled       = true;
            }
            var lastLogon = ConvertToUnixEpoch(entry.GetProp("lastlogon"));
            var lastSet   = ConvertToUnixEpoch(entry.GetProp("pwdlastset"));
            var sid       = entry.GetSid();
            var os        = entry.GetProp("operatingsystem");
            var sp        = entry.GetProp("operatingsystemservicepack");
            var domainS   = resolved.BloodHoundDisplay.Split('.');

            domainS = domainS.Skip(1).ToArray();
            var domain = string.Join(".", domainS).ToUpper();

            if (sp != null)
            {
                os = $"{os} {sp}";
            }

            return(new ComputerProp
            {
                ComputerName = resolved.BloodHoundDisplay,
                Enabled = enabled,
                LastLogon = lastLogon,
                ObjectSid = sid,
                OperatingSystem = os,
                PwdLastSet = lastSet,
                UnconstrainedDelegation = unconstrained,
                Domain = domain
            });
        }
예제 #8
0
        public static UserProp GetUserProps(SearchResultEntry entry, ResolvedEntry resolved)
        {
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled = (flags & UacFlags.AccountDisable) == 0;
            }
            else
            {
                enabled = true;
            }
            var history          = entry.GetPropBytes("sidhistory");
            var lastlogon        = entry.GetProp("lastlogon");
            var pwdlastset       = entry.GetProp("pwdlastset");
            var spn              = entry.GetPropArray("serviceprincipalname");
            var displayName      = entry.GetProp("displayname");
            var hasSpn           = spn.Length != 0;
            var spnString        = string.Join("|", spn);
            var convertedlogon   = ConvertToUnixEpoch(lastlogon);
            var convertedlastset = ConvertToUnixEpoch(pwdlastset);
            var sid              = entry.GetSid();
            var sidhistory       = history != null ? new SecurityIdentifier(history, 0).Value : "";
            var mail             = entry.GetProp("mail");
            var domain           = resolved.BloodHoundDisplay.Split('@')[1].ToUpper();

            return(new UserProp
            {
                AccountName = resolved.BloodHoundDisplay,
                Enabled = enabled,
                LastLogon = convertedlogon,
                ObjectSid = sid,
                PwdLastSet = convertedlastset,
                SidHistory = sidhistory,
                HasSpn = hasSpn,
                ServicePrincipalNames = spnString,
                DisplayName = displayName,
                Email = mail,
                Domain = domain
            });
        }
예제 #9
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref Group obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }
            var ac = entry.GetProp("admincount");

            if (ac != null)
            {
                var a = int.Parse(ac);
                obj.Properties.Add("admincount", a != 0);
            }
            else
            {
                obj.Properties.Add("admincount", false);
            }

            obj.Properties.Add("description", entry.GetProp("description"));
        }
예제 #10
0
        internal static void GetGroupInfo(SearchResultEntry entry, ResolvedEntry resolved, string domainSid, ref Computer u)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.Group))
            {
                return;
            }

            var pgi = entry.GetProp("primarygroupid");

            if (pgi == null)
            {
                return;
            }

            var pgsid            = $"{domainSid}-{pgi}";
            var primaryGroupName = _utils.SidToDisplay(pgsid, Utils.ConvertDnToDomain(entry.DistinguishedName), Props, "group");

            u.PrimaryGroup = primaryGroupName;
        }
예제 #11
0
        /// <summary>
        /// Processes the ACL entries for an AD object
        /// </summary>
        /// <param name="entry">LDAP entry to process</param>
        /// <param name="domainName">Domain name the entry belongs too</param>
        /// <returns>A list of ACL objects for the entry</returns>
        public static IEnumerable <ACL> ProcessAdObject(SearchResultEntry entry, string domainName)
        {
            var ntSecurityDescriptor = entry.GetPropBytes("ntsecuritydescriptor");

            //If the ntsecuritydescriptor is null, no point in continuing
            //I'm still not entirely sure what causes this, but it can happen
            if (ntSecurityDescriptor == null)
            {
                yield break;
            }

            //Convert the ntsecuritydescriptor bytes to a .net object
            var descriptor = new RawSecurityDescriptor(ntSecurityDescriptor, 0);

            //Grab the DACL
            var rawAcl = descriptor.DiscretionaryAcl;
            //Grab the Owner
            var ownerSid = descriptor.Owner.ToString();

            //Resolve the entry name/type
            var resolvedEntry = entry.ResolveAdEntry();

            //If our name is null, we dont know what the principal is
            if (resolvedEntry == null)
            {
                yield break;
            }

            var    entryDisplayName = resolvedEntry.BloodHoundDisplay;
            var    entryType        = resolvedEntry.ObjectType;
            string entryGuid;

            if (entryType.Equals("gpo"))
            {
                var n = entry.GetProp("name").ToUpper();
                entryGuid = n.Substring(1, n.Length - 2);
            }
            else
            {
                entryGuid = "";
            }

            //We have no exploitable paths for Computer, so just ignore them
            if (entryType.Equals("computer"))
            {
                yield break;
            }

            //Determine the owner of the object. Start by checking if we've already determined this is null
            if (!_nullSids.TryGetValue(ownerSid, out byte _))
            {
                //Check if its a common SID
                if (!MappedPrincipal.GetCommon(ownerSid, out var owner))
                {
                    //Resolve the sid manually if we still dont have it
                    var ownerDomain = _utils.SidToDomainName(ownerSid) ?? domainName;
                    owner = _utils.UnknownSidTypeToDisplay(ownerSid, ownerDomain, Props);
                }
                else
                {
                    owner.PrincipalName = $"{owner.PrincipalName}@{domainName}";
                }

                //Filter out the Local System principal which pretty much every entry has
                if (owner != null && !owner.PrincipalName.Contains("Local System"))
                {
                    yield return(new ACL
                    {
                        PrincipalName = owner.PrincipalName,
                        PrincipalType = owner.ObjectType,
                        Inherited = false,
                        RightName = "Owner",
                        AceType = "",
                        ObjectName = entryDisplayName,
                        ObjectType = entryType,
                        Qualifier = "AccessAllowed",
                        ObjectGuid = entryGuid
                    });
                }
                else
                {
                    //We'll cache SIDs we've failed to resolve previously so we dont keep trying
                    _nullSids.TryAdd(ownerSid, new byte());
                }
            }

            //Loop over the actual entries in the DACL
            foreach (var genericAce in rawAcl)
            {
                var qAce      = (QualifiedAce)genericAce;
                var objectSid = qAce.SecurityIdentifier.ToString();

                //If this is something we already resolved to null, just keep on moving
                if (_nullSids.TryGetValue(objectSid, out byte _))
                {
                    continue;
                }

                //Check if its a common sid
                if (!MappedPrincipal.GetCommon(objectSid, out var mappedPrincipal))
                {
                    //If not common, lets resolve it normally
                    var objectDomain =
                        _utils.SidToDomainName(objectSid) ??
                        domainName;
                    mappedPrincipal = _utils.UnknownSidTypeToDisplay(objectSid, objectDomain, Props);
                    if (mappedPrincipal == null)
                    {
                        _nullSids.TryAdd(objectSid, new byte());
                        continue;
                    }
                }
                else
                {
                    mappedPrincipal.PrincipalName = $"{mappedPrincipal.PrincipalName}@{domainName}";
                }

                //bf967a86-0de6-11d0-a285-00aa003049e2 - Computer
                //bf967aba-0de6-11d0-a285-00aa003049e2 - User
                //bf967a9c-0de6-11d0-a285-00aa003049e2 - Group
                //19195a5a-6da0-11d0-afd3-00c04fd930c9 - Domain
                //f30e3bc2-9ff0-11d1-b603-0000f80367c1 - GPC

                if (mappedPrincipal.PrincipalName.Contains("Local System"))
                {
                    continue;
                }

                //We have a principal and we've successfully resolved the object. Lets process stuff!

                //Convert our right to an ActiveDirectoryRight enum object, and then to a string
                var adRight       = (ActiveDirectoryRights)Enum.ToObject(typeof(ActiveDirectoryRights), qAce.AccessMask);
                var adRightString = adRight.ToString();

                //Get the ACE for our right
                var ace  = qAce as ObjectAce;
                var guid = ace != null?ace.ObjectAceType.ToString() : "";

                var toContinue = false;

                //Figure out if we need more processing by matching the right name + guid together
                toContinue |= (adRightString.Contains("WriteDacl") || adRightString.Contains("WriteOwner"));
                if (adRightString.Contains("GenericWrite") || adRightString.Contains("GenericAll"))
                {
                    toContinue |= ("00000000-0000-0000-0000-000000000000".Equals(guid) || guid.Equals("") || toContinue);
                }

                if (adRightString.Contains("ExtendedRight"))
                {
                    toContinue |= (guid.Equals("00000000-0000-0000-0000-000000000000") || guid.Equals("") ||
                                   guid.Equals("00299570-246d-11d0-a768-00aa006e0529") || toContinue);

                    //DCSync rights
                    toContinue |= (guid.Equals("1131f6aa-9c07-11d1-f79f-00c04fc2dcd2") ||
                                   guid.Equals("1131f6ad-9c07-11d1-f79f-00c04fc2dcd2") || toContinue);
                }

                if (adRightString.Contains("WriteProperty"))
                {
                    toContinue |= (guid.Equals("00000000-0000-0000-0000-000000000000") ||
                                   guid.Equals("bf9679c0-0de6-11d0-a285-00aa003049e2") ||
                                   guid.Equals("bf9679a8-0de6-11d0-a285-00aa003049e2") ||
                                   guid.Equals("f30e3bc1-9ff0-11d1-b603-0000f80367c1") || toContinue);
                }

                var inheritedObjectType = ace != null?ace.InheritedObjectAceType.ToString() : "00000000-0000-0000-0000-000000000000";

                var isInherited = false;

                switch (entryType)
                {
                case "user":
                    isInherited = inheritedObjectType.Equals("00000000-0000-0000-0000-000000000000") ||
                                  inheritedObjectType.Equals("bf967aba-0de6-11d0-a285-00aa003049e2");
                    break;

                case "group":
                    isInherited = inheritedObjectType.Equals("00000000-0000-0000-0000-000000000000") ||
                                  inheritedObjectType.Equals("bf967a9c-0de6-11d0-a285-00aa003049e2");
                    break;

                case "domain":
                    isInherited = inheritedObjectType.Equals("00000000-0000-0000-0000-000000000000") ||
                                  inheritedObjectType.Equals("19195a5a-6da0-11d0-afd3-00c04fd930c9");
                    break;

                case "gpo":
                    isInherited = inheritedObjectType.Equals("00000000-0000-0000-0000-000000000000") ||
                                  inheritedObjectType.Equals("f30e3bc2-9ff0-11d1-b603-0000f80367c1");
                    break;
                }

                if (!toContinue || !isInherited)
                {
                    continue;
                }

                string aceType = null;
                if (adRightString.Contains("ExtendedRight"))
                {
                    switch (guid)
                    {
                    case "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2":
                        aceType = "DS-Replication-Get-Changes";
                        break;

                    case "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2":
                        aceType = "DS-Replication-Get-Changes-All";
                        break;

                    default:
                        aceType = "All";
                        break;
                    }
                }

                //If we have either of the DCSync rights, store it in a temporary object and continue.
                //We need both rights for either right to mean anything to us
                if (aceType != null && entryType.Equals("domain") && (aceType.Equals("DS-Replication-Get-Changes-All") ||
                                                                      aceType.Equals("DS-Replication-Get-Changes")))
                {
                    if (!_syncers.TryGetValue(mappedPrincipal.PrincipalName, out var sync))
                    {
                        sync = new DcSync
                        {
                            Domain        = entryDisplayName,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType
                        };
                    }

                    if (aceType.Contains("-All"))
                    {
                        sync.GetChangesAll = true;
                    }
                    else
                    {
                        sync.GetChanges = true;
                    }

                    _syncers.AddOrUpdate(mappedPrincipal.PrincipalName, sync, (key, oldVar) => sync);
                    continue;
                }

                if (aceType != null && entryType.Equals("domain") && aceType.Equals("All"))
                {
                    if (!_syncers.TryGetValue(mappedPrincipal.PrincipalName, out var sync))
                    {
                        sync = new DcSync
                        {
                            Domain        = entryDisplayName,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType
                        };
                    }

                    sync.GetChangesAll = true;
                    sync.GetChanges    = true;

                    _syncers.AddOrUpdate(mappedPrincipal.PrincipalName, sync, (key, oldVar) => sync);
                }

                if (aceType != null && entryType.Equals("domain") && adRightString.Contains("GenericAll"))
                {
                    if (!_syncers.TryGetValue(mappedPrincipal.PrincipalName, out var sync))
                    {
                        sync = new DcSync
                        {
                            Domain        = entryDisplayName,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType
                        };
                    }

                    sync.GetChangesAll = true;
                    sync.GetChanges    = true;

                    _syncers.AddOrUpdate(mappedPrincipal.PrincipalName, sync, (key, oldVar) => sync);
                }

                //Return ACL objects based on rights + guid combos

                if (adRightString.Contains("GenericAll"))
                {
                    yield return(new ACL
                    {
                        AceType = "",
                        Inherited = qAce.IsInherited,
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        ObjectType = entryType,
                        ObjectName = entryDisplayName,
                        RightName = "GenericAll",
                        Qualifier = qAce.AceQualifier.ToString(),
                        ObjectGuid = entryGuid
                    });
                }

                if (adRightString.Contains("GenericWrite"))
                {
                    yield return(new ACL
                    {
                        AceType = "",
                        Inherited = qAce.IsInherited,
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        ObjectType = entryType,
                        ObjectName = entryDisplayName,
                        RightName = "GenericWrite",
                        Qualifier = qAce.AceQualifier.ToString(),
                        ObjectGuid = entryGuid
                    });
                }

                if (adRightString.Contains("WriteOwner"))
                {
                    yield return(new ACL
                    {
                        AceType = "",
                        Inherited = qAce.IsInherited,
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        ObjectType = entryType,
                        ObjectName = entryDisplayName,
                        RightName = "WriteOwner",
                        Qualifier = qAce.AceQualifier.ToString(),
                        ObjectGuid = entryGuid
                    });
                }

                if (adRightString.Contains("WriteDacl"))
                {
                    yield return(new ACL
                    {
                        AceType = "",
                        Inherited = qAce.IsInherited,
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        ObjectType = entryType,
                        ObjectName = entryDisplayName,
                        RightName = "WriteDacl",
                        Qualifier = qAce.AceQualifier.ToString(),
                        ObjectGuid = entryGuid
                    });
                }

                if (adRightString.Contains("WriteProperty"))
                {
                    if (guid.Equals("bf9679c0-0de6-11d0-a285-00aa003049e2") && !entryType.Equals("domain") && !entryType.Equals("gpo"))
                    {
                        yield return(new ACL
                        {
                            AceType = "Member",
                            Inherited = qAce.IsInherited,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            ObjectType = entryType,
                            ObjectName = entryDisplayName,
                            RightName = "WriteProperty",
                            Qualifier = qAce.AceQualifier.ToString(),
                            ObjectGuid = entryGuid
                        });
                    }
                    //else if (guid.Equals("f30e3bc1-9ff0-11d1-b603-0000f80367c1") && entryType.Equals("gpo"))
                    //{
                    //    yield return new ACL
                    //    {
                    //        AceType = "GPC-File-Sys-Path",
                    //        Inherited = qAce.IsInherited,
                    //        PrincipalName = mappedPrincipal.PrincipalName,
                    //        PrincipalType = mappedPrincipal.ObjectType,
                    //        ObjectType = entryType,
                    //        ObjectName = entryDisplayName,
                    //        RightName = "WriteProperty",
                    //        Qualifier = qAce.AceQualifier.ToString(),
                    //        ObjectGuid = entryGuid
                    //    };
                    //}
                }

                if (adRightString.Contains("ExtendedRight"))
                {
                    if (guid.Equals("00299570-246d-11d0-a768-00aa006e0529") && !entryType.Equals("domain") && !entryType.Equals("gpo"))
                    {
                        yield return(new ACL
                        {
                            AceType = "User-Force-Change-Password",
                            Inherited = qAce.IsInherited,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            ObjectType = entryType,
                            ObjectName = entryDisplayName,
                            RightName = "ExtendedRight",
                            Qualifier = qAce.AceQualifier.ToString(),
                            ObjectGuid = entryGuid
                        });
                    }
                    else if (guid.Equals("00000000-0000-0000-0000-000000000000"))
                    {
                        yield return(new ACL
                        {
                            AceType = "All",
                            Inherited = qAce.IsInherited,
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            ObjectType = entryType,
                            ObjectName = entryDisplayName,
                            RightName = "ExtendedRight",
                            Qualifier = qAce.AceQualifier.ToString(),
                            ObjectGuid = entryGuid
                        });
                    }
                }
            }
        }
예제 #12
0
        //public static List<LocalAdmin> LocalGroupWinNt(string target, string group)
        //{
        //    var members = new DirectoryEntry($"WinNT://{target}/{group},group");
        //    var localAdmins = new List<LocalAdmin>();
        //    try
        //    {
        //        foreach (var member in (System.Collections.IEnumerable)members.Invoke("Members"))
        //        {
        //            using (var m = new DirectoryEntry(member))
        //            {
        //                //Convert sid bytes to a string
        //                var sidstring = new SecurityIdentifier(m.GetSid(), 0).ToString();
        //                string type;
        //                switch (m.SchemaClassName)
        //                {
        //                    case "Group":
        //                        type = "group";
        //                        break;
        //                    case "User":
        //                        //If its a user but the name ends in $, it's actually a computer (probably)
        //                        type = m.Properties["Name"][0].ToString().EndsWith("$", StringComparison.Ordinal) ? "computer" : "user";
        //                        break;
        //                    default:
        //                        type = "group";
        //                        break;
        //                }

        //                //Start by checking the cache
        //                if (!_cache.GetMapValue(sidstring, type, out var adminName))
        //                {
        //                    //Get the domain from the SID
        //                    var domainName = _utils.SidToDomainName(sidstring);

        //                    //Search for the object in AD
        //                    var entry = _utils
        //                        .DoSearch($"(objectsid={sidstring})", SearchScope.Subtree, AdminProps, domainName)
        //                        .DefaultIfEmpty(null).FirstOrDefault();

        //                    //If it's not null, we have an object, yay! Otherwise, meh
        //                    if (entry != null)
        //                    {
        //                        adminName = entry.ResolveAdEntry().BloodHoundDisplay;
        //                        _cache.AddMapValue(sidstring, type, adminName);
        //                    }
        //                    else
        //                    {
        //                        adminName = null;
        //                    }
        //                }

        //                if (adminName != null)
        //                {
        //                    localAdmins.Add(new LocalAdmin { ObjectName = adminName, ObjectType = type, Server = target });
        //                }
        //            }
        //        }
        //    }
        //    catch (COMException)
        //    {
        //        //You can get a COMException, so just return a blank array
        //        return localAdmins;
        //    }

        //    return localAdmins;
        //}

        //public static List<LocalAdmin> LocalGroupApi(string target, string group, string domainName, string domainSid)
        //{
        //    const int queryLevel = 2;
        //    var resumeHandle = IntPtr.Zero;
        //    var machineSid = "DUMMYSTRING";

        //    var LMI2 = typeof(LOCALGROUP_MEMBERS_INFO_2);

        //    var returnValue = NetLocalGroupGetMembers(target, group, queryLevel, out IntPtr ptrInfo, -1, out int entriesRead, out int _, resumeHandle);

        //    //Return value of 1722 indicates the system is down, so no reason to fallback to WinNT
        //    if (returnValue == 1722)
        //    {
        //        throw new SystemDownException();
        //    }

        //    //If its not 0, something went wrong, but we can fallback to WinNT provider. Throw an exception
        //    if (returnValue != 0)
        //    {
        //        throw new ApiFailedException();
        //    }

        //    var toReturn = new List<LocalAdmin>();

        //    if (entriesRead <= 0) return toReturn;

        //    var iter = ptrInfo;
        //    var list = new List<API_Encapsulator>();

        //    //Loop through the data and save them into a list for processing
        //    for (var i = 0; i < entriesRead; i++)
        //    {
        //        var data = (LOCALGROUP_MEMBERS_INFO_2)Marshal.PtrToStructure(iter, LMI2);
        //        ConvertSidToStringSid(data.lgrmi2_sid, out string sid);
        //        list.Add(new API_Encapsulator
        //        {
        //            Lgmi2 = data,
        //            sid = sid
        //        });
        //        iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(LMI2));
        //    }

        //    NetApiBufferFree(ptrInfo);
        //    //Try and determine the machine sid

        //    foreach (var data in list)
        //    {
        //        if (data.sid == null)
        //        {
        //            continue;
        //        }

        //        //If the sid ends with -500 and doesn't start with the DomainSID, there's a very good chance we've identified the RID500 account
        //        //Take the machine sid from there. If we don't find it, we use a dummy string
        //        if (!data.sid.EndsWith("-500", StringComparison.Ordinal) ||
        //            data.sid.StartsWith(domainSid, StringComparison.Ordinal)) continue;
        //        machineSid = new SecurityIdentifier(data.sid).AccountDomainSid.Value;
        //        break;
        //    }

        //    foreach (var data in list)
        //    {
        //        if (data.sid == null)
        //            continue;
        //        var objectName = data.Lgmi2.lgrmi2_domainandname;
        //        if (objectName.Split('\\').Last().Equals(""))
        //        {
        //            //Sometimes we get weird objects that are just a domain name with no user behind it.
        //            continue;
        //        }

        //        if (data.sid.StartsWith(machineSid, StringComparison.Ordinal))
        //        {
        //            //This should filter out local accounts
        //            continue;
        //        }

        //        string type;
        //        switch (data.Lgmi2.lgrmi2_sidusage)
        //        {
        //            case SID_NAME_USE.SidTypeUser:
        //                type = "user";
        //                break;
        //            case SID_NAME_USE.SidTypeGroup:
        //                type = "group";
        //                break;
        //            case SID_NAME_USE.SidTypeComputer:
        //                type = "computer";
        //                break;
        //            case SID_NAME_USE.SidTypeWellKnownGroup:
        //                type = "wellknown";
        //                break;
        //            default:
        //                type = null;
        //                break;
        //        }

        //        //I have no idea what would cause this condition
        //        if (type == null)
        //        {
        //            continue;
        //        }

        //        if (objectName.EndsWith("$", StringComparison.Ordinal))
        //        {
        //            type = "computer";
        //        }

        //        var resolved = _utils.SidToDisplay(data.sid, _utils.SidToDomainName(data.sid), AdminProps, type);
        //        if (resolved == null)
        //        {
        //            continue;
        //        }

        //        toReturn.Add(new LocalAdmin
        //        {
        //            ObjectName = resolved,
        //            ObjectType = type,
        //            Server = target
        //        });
        //    }
        //    return toReturn;
        //}
        #endregion

        public static IEnumerable <LocalAdmin> GetGpoAdmins(SearchResultEntry entry, string domainName)
        {
            const string targetSid = "S-1-5-32-544__Members";

            var displayName = entry.GetProp("displayname");
            var name        = entry.GetProp("name");
            var path        = entry.GetProp("gpcfilesyspath");


            if (displayName == null || name == null || path == null)
            {
                yield break;
            }

            var resolvedList = new List <MappedPrincipal>();

            var template       = $"{path}\\MACHINE\\Microsoft\\Windows NT\\SecEdit\\GptTmpl.inf";
            var currentSection = string.Empty;

            if (File.Exists(template))
            {
                using (var reader = new StreamReader(template))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        var sMatch = SectionRegex.Match(line);
                        if (sMatch.Success)
                        {
                            currentSection = sMatch.Captures[0].Value.Trim();
                        }

                        if (!currentSection.Equals("[Group Membership]"))
                        {
                            continue;
                        }

                        var kMatch = KeyRegex.Match(line);

                        if (!kMatch.Success)
                        {
                            continue;
                        }

                        var n = kMatch.Groups[1].Value;
                        var v = kMatch.Groups[2].Value;

                        if (!n.Contains(targetSid))
                        {
                            continue;
                        }

                        v = v.Trim();
                        var members = v.Split(',');


                        foreach (var m in members)
                        {
                            var    member = m.Trim('*');
                            string sid;
                            if (!member.StartsWith("S-1-", StringComparison.CurrentCulture))
                            {
                                try
                                {
                                    sid = new NTAccount(domainName, m).Translate(typeof(SecurityIdentifier)).Value;
                                }
                                catch
                                {
                                    sid = null;
                                }
                            }
                            else
                            {
                                sid = member;
                            }

                            if (sid == null)
                            {
                                continue;
                            }

                            var domain            = _utils.SidToDomainName(sid) ?? domainName;
                            var resolvedPrincipal = _utils.UnknownSidTypeToDisplay(sid, domain, Props);
                            if (resolvedPrincipal != null)
                            {
                                resolvedList.Add(resolvedPrincipal);
                            }
                        }
                    }
                }
            }

            var xml = $"{path}\\USER\\Preferences\\Groups\\Groups.xml";

            if (File.Exists(xml))
            {
                var doc   = new XPathDocument(xml);
                var nav   = doc.CreateNavigator();
                var nodes = nav.Select("/Groups/Group");

                while (nodes.MoveNext())
                {
                    var properties = nodes.Current.Select("Properties");
                    while (properties.MoveNext())
                    {
                        var groupSid = properties.Current.GetAttribute("groupSid", "");
                        if (groupSid == "")
                        {
                            continue;
                        }

                        if (!groupSid.Equals("S-1-5-32-544"))
                        {
                            continue;
                        }


                        var members = properties.Current.Select("Members");
                        while (members.MoveNext())
                        {
                            var subMembers = members.Current.Select("Member");
                            while (subMembers.MoveNext())
                            {
                                var action = subMembers.Current.GetAttribute("action", "");
                                if (action.Equals("ADD"))
                                {
                                    var sid = subMembers.Current.GetAttribute("sid", "");
                                    if (sid == "")
                                    {
                                        continue;
                                    }
                                    var domain            = _utils.SidToDomainName(sid) ?? domainName;
                                    var resolvedPrincipal = _utils.UnknownSidTypeToDisplay(sid, domain, Props);
                                    if (resolvedPrincipal != null)
                                    {
                                        resolvedList.Add(resolvedPrincipal);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (resolvedList.Count > 0)
            {
                foreach (var ouObject in _utils.DoSearch($"(gplink=*{name}*)", SearchScope.Subtree, GpLinkProps, domainName))
                {
                    var adspath = ouObject.DistinguishedName;

                    foreach (var compEntry in _utils.DoSearch("(objectclass=computer)", SearchScope.Subtree, GpoProps,
                                                              domainName, adspath))
                    {
                        var samAccountType = compEntry.GetProp("samaccounttype");
                        if (samAccountType == null || samAccountType != "805306369")
                        {
                            continue;
                        }

                        var server = compEntry.ResolveAdEntry()?.BloodHoundDisplay;

                        if (server == null)
                        {
                            continue;
                        }

                        foreach (var user in resolvedList)
                        {
                            yield return(new LocalAdmin
                            {
                                ObjectName = user.PrincipalName,
                                ObjectType = user.ObjectType,
                                Server = server
                            });
                        }
                    }
                }
            }
        }
예제 #13
0
        /// <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
                       }
            }
            ;
        }
예제 #14
0
        internal static void ResolveContainer(SearchResultEntry entry, ResolvedEntry resolved, ref Ou obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.Container))
            {
                return;
            }

            var domain = Utils.ConvertDnToDomain(entry.DistinguishedName);

            var opts = entry.GetProp("gpoptions");

            obj.Properties.Add("blocksinheritance", opts != null && opts.Equals("1"));

            //Resolve GPLinks on the ou
            var links = new List <GpLink>();

            var gpLinks = entry.GetProp("gplink");

            if (gpLinks != null)
            {
                foreach (var l in gpLinks.Split(']', '[').Where(x => x.StartsWith("LDAP")))
                {
                    var split  = l.Split(';');
                    var dn     = split[0];
                    var status = split[1];
                    if (status.Equals("3") || status.Equals("1"))
                    {
                        continue;
                    }

                    var enforced = status.Equals("2");
                    var index    = dn.IndexOf("CN=", StringComparison.OrdinalIgnoreCase) + 4;
                    var name     = dn.Substring(index, index + 25);

                    if (!_gpoCache.ContainsKey(name))
                    {
                        continue;
                    }

                    var dName = _gpoCache[name];
                    links.Add(new GpLink
                    {
                        IsEnforced = enforced,
                        Name       = $"{dName}@{domain}"
                    });
                }

                obj.Links = links.ToArray();
            }

            var computers = new List <string>();
            var users     = new List <string>();
            var ous       = new List <string>();

            foreach (var subEntry in _utils.DoSearch(
                         "(|(samAccountType=805306368)(samAccountType=805306369)(objectclass=organizationalUnit))",
                         SearchScope.OneLevel,
                         new[]
            {
                "samaccountname", "name", "objectguid", "objectclass", "objectsid", "samaccounttype", "dnshostname"
            }, domain, entry.DistinguishedName))
            {
                var subResolved = subEntry.ResolveAdEntry();

                if (subResolved == null)
                {
                    continue;
                }

                if (subResolved.ObjectType.Equals("ou"))
                {
                    ous.Add(new Guid(subEntry.GetPropBytes("objectguid")).ToString().ToUpper());
                }
                else if (subResolved.ObjectType.Equals("computer"))
                {
                    computers.Add(subResolved.BloodHoundDisplay);
                }
                else
                {
                    users.Add(subResolved.BloodHoundDisplay);
                }
            }

            obj.Users = users.ToArray();

            obj.Computers = computers.ToArray();

            obj.ChildOus = ous.ToArray();
        }
예제 #15
0
        /// <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
                       }
            }
            ;
        }
예제 #16
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref Computer obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled, unconstrained, trustedToAuth;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled       = (flags & UacFlags.AccountDisable) == 0;
                unconstrained = (flags & UacFlags.TrustedForDelegation) == UacFlags.TrustedForDelegation;
                trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0;
            }
            else
            {
                unconstrained = false;
                enabled       = true;
                trustedToAuth = false;
            }

            var comps = new List <string>();

            if (trustedToAuth)
            {
                var delegates = entry.GetPropArray("msds-allowedToDelegateTo");
                obj.Properties.Add("allowedtodelegate", delegates);

                foreach (var d in delegates)
                {
                    var hname = d.Contains("/") ? d.Split('/')[1] : d;
                    hname = hname.Split(':')[0];
                    var resolvedHost = Utils.Instance.ResolveHost(hname);
                    if (resolvedHost.Contains("."))
                    {
                        comps.Add(resolvedHost.ToUpper());
                    }
                }
            }
            obj.AllowedToDelegate = comps.Distinct().ToArray();

            var allowedToAct = entry.GetPropBytes("msDS-AllowedToActOnBehalfOfOtherIdentity");

            if (allowedToAct != null)
            {
                var principals = new List <LocalMember>();
                var sd         = new ActiveDirectorySecurity();
                sd.SetSecurityDescriptorBinaryForm(allowedToAct, AccessControlSections.Access);
                var utils = Utils.Instance;
                foreach (ActiveDirectoryAccessRule rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier)))
                {
                    var sid    = rule.IdentityReference.Value;
                    var domain = utils.SidToDomainName(sid) ?? Utils.ConvertDnToDomain(entry.DistinguishedName);
                    if (!MappedPrincipal.GetCommon(sid, out var principal))
                    {
                        principal = utils.UnknownSidTypeToDisplay(sid, domain, Props);
                    }
                    else
                    {
                        if (sid == "S-1-5-9")
                        {
                            var dObj = utils.GetForest(domain);
                            var d    = dObj == null ? domain : dObj.RootDomain.Name;
                            principal.PrincipalName = $"ENTERPRISE DOMAIN CONTROLLERS@{d}".ToUpper();
                        }
                        else
                        {
                            principal.PrincipalName = $"{principal.PrincipalName}@{domain}".ToUpper();
                        }
                    }

                    if (principal == null)
                    {
                        continue;
                    }

                    principals.Add(new LocalMember
                    {
                        Name = principal.PrincipalName,
                        Type = principal.ObjectType
                    });
                }

                obj.AllowedToAct = principals.ToArray();
            }

            obj.Properties.Add("enabled", enabled);
            obj.Properties.Add("unconstraineddelegation", unconstrained);
            obj.Properties.Add("lastlogon", ConvertToUnixEpoch(entry.GetProp("lastlogon")));
            obj.Properties.Add("lastlogontimestamp", ConvertToUnixEpoch(entry.GetProp("lastlogontimestamp")));
            obj.Properties.Add("pwdlastset", ConvertToUnixEpoch(entry.GetProp("pwdlastset")));
            obj.Properties.Add("serviceprincipalnames", entry.GetPropArray("serviceprincipalname"));
            var os = entry.GetProp("operatingsystem");
            var sp = entry.GetProp("operatingsystemservicepack");

            if (sp != null)
            {
                os = $"{os} {sp}";
            }

            obj.Properties.Add("operatingsystem", os);
            obj.Properties.Add("description", entry.GetProp("description"));
        }
예제 #17
0
        internal static LdapWrapper FindLdapType(SearchResultEntry searchResultEntry)
        {
            //Look for a null DN first. Not sure why this would happen.
            var distinguishedName = searchResultEntry.DistinguishedName;

            if (distinguishedName == null)
            {
                return(null);
            }

            var accountName    = searchResultEntry.GetProp("samaccountname");
            var samAccountType = searchResultEntry.GetProp("samaccounttype");
            var accountDomain  = Helpers.DistinguishedNameToDomain(distinguishedName);
            var objectSid      = searchResultEntry.GetSid();
            var objectType     = LdapTypeEnum.Unknown;

            LdapWrapper wrapper;

            //Lets see if its a "common" principal
            if (CommonPrincipal.GetCommonSid(objectSid, out var commonPrincipal))
            {
                accountName = commonPrincipal.Name;
                objectType  = commonPrincipal.Type;
            }
            else
            {
                //Its not a common principal. Lets use properties to figure out what it actually is
                if (samAccountType != null)
                {
                    if (samAccountType == "805306370")
                    {
                        return(null);
                    }

                    objectType = Helpers.SamAccountTypeToType(samAccountType);
                }
                else
                {
                    var objectClasses = searchResultEntry.GetPropArray("objectClass");
                    if (objectClasses == null)
                    {
                        objectType = LdapTypeEnum.Unknown;
                    }
                    else if (objectClasses.Contains("groupPolicyContainer"))
                    {
                        objectType = LdapTypeEnum.GPO;
                    }
                    else if (objectClasses.Contains("organizationalUnit"))
                    {
                        objectType = LdapTypeEnum.OU;
                    }
                    else if (objectClasses.Contains("domain"))
                    {
                        objectType = LdapTypeEnum.Domain;
                    }
                }
            }

            //Depending on the object type, create the appropriate wrapper object
            switch (objectType)
            {
            case LdapTypeEnum.Computer:
                accountName = accountName?.TrimEnd('$');
                wrapper     = new Computer(searchResultEntry)
                {
                    DisplayName = $"{accountName}.{accountDomain}"
                };
                break;

            case LdapTypeEnum.User:
                wrapper = new User(searchResultEntry)
                {
                    DisplayName = $"{accountName}@{accountDomain}"
                };
                break;

            case LdapTypeEnum.Group:
                wrapper = new Group(searchResultEntry)
                {
                    DisplayName = $"{accountName}@{accountDomain}"
                };
                break;

            case LdapTypeEnum.GPO:
                accountName = searchResultEntry.GetProp("displayname");
                wrapper     = new GPO(searchResultEntry)
                {
                    DisplayName = $"{accountName}@{accountDomain}"
                };
                break;

            case LdapTypeEnum.OU:
                accountName = searchResultEntry.GetProp("name");
                wrapper     = new OU(searchResultEntry)
                {
                    DisplayName = $"{accountName}@{accountDomain}"
                };
                break;

            case LdapTypeEnum.Domain:
                wrapper = new Domain(searchResultEntry)
                {
                    DisplayName = accountDomain
                };
                break;

            case LdapTypeEnum.Unknown:
                wrapper = null;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            //Set the DN/SID for the wrapper going forward
            if (wrapper == null)
            {
                return(wrapper);
            }
            wrapper.DistinguishedName  = distinguishedName;
            wrapper.SecurityIdentifier = objectSid;

            //Return our wrapper for the next step in the pipeline
            return(wrapper);
        }
예제 #18
0
        internal static void GetProps(SearchResultEntry entry, ResolvedEntry resolved, ref User obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ObjectProps))
            {
                return;
            }
            var  uac = entry.GetProp("useraccountcontrol");
            bool enabled, trustedToAuth;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled       = (flags & UacFlags.AccountDisable) == 0;
                trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0;
            }
            else
            {
                trustedToAuth = false;
                enabled       = true;
            }

            var comps = new List <string>();

            if (trustedToAuth)
            {
                var delegates = entry.GetPropArray("msds-allowedToDelegateTo");
                obj.Properties.Add("allowedtodelegate", delegates);

                foreach (var d in delegates)
                {
                    var hname = d.Contains("/") ? d.Split('/')[1] : d;
                    hname = hname.Split(':')[0];
                    var resolvedHost = Utils.Instance.ResolveHost(hname);
                    if (resolvedHost.Contains("."))
                    {
                        comps.Add(resolvedHost.ToUpper());
                    }
                }
            }
            obj.AllowedToDelegate = comps.Distinct().ToArray();

            obj.Properties.Add("enabled", enabled);
            //var history = entry.GetPropBytes("sidhistory");
            //obj.SidHistory = history != null ? new SecurityIdentifier(history, 0).Value : "";
            obj.Properties.Add("lastlogon", ConvertToUnixEpoch(entry.GetProp("lastlogon")));
            obj.Properties.Add("pwdlastset", ConvertToUnixEpoch(entry.GetProp("pwdlastset")));
            var spn = entry.GetPropArray("serviceprincipalname");

            obj.Properties.Add("serviceprincipalnames", spn);
            obj.Properties.Add("hasspn", spn.Length > 0);
            obj.Properties.Add("displayname", entry.GetProp("displayname"));
            obj.Properties.Add("email", entry.GetProp("mail"));
            obj.Properties.Add("title", entry.GetProp("title"));
            obj.Properties.Add("homedirectory", entry.GetProp("homedirectory"));
            obj.Properties.Add("description", entry.GetProp("description"));
            obj.Properties.Add("userpassword", entry.GetProp("userpassword"));
            var ac = entry.GetProp("admincount");

            if (ac != null)
            {
                var a = int.Parse(ac);
                obj.Properties.Add("admincount", a != 0);
            }
            else
            {
                obj.Properties.Add("admincount", false);
            }
        }
예제 #19
0
        internal static ResolvedEntry ResolveAdEntry(this SearchResultEntry result, bool bypassDns = false)
        {
            var entry = new ResolvedEntry();

            var accountName       = result.GetProp("samaccountname");
            var distinguishedName = result.DistinguishedName;
            var accountType       = result.GetProp("samaccounttype");

            if (distinguishedName == null)
            {
                return(null);
            }

            var domainName = Utils.ConvertDnToDomain(distinguishedName);

            if (MappedPrincipal.GetCommon(result.GetSid(), out var temp))
            {
                return(new ResolvedEntry
                {
                    IngestCacheDisplay = $"{temp.PrincipalName}@{domainName}".ToUpper(),
                    ObjectType = temp.ObjectType
                });
            }

            if (Groups.Contains(accountType))
            {
                entry.IngestCacheDisplay = $"{accountName}@{domainName}".ToUpper();
                entry.ObjectType         = "group";
                return(entry);
            }

            if (Users.Contains(accountType))
            {
                entry.IngestCacheDisplay = $"{accountName}@{domainName}".ToUpper();
                entry.ObjectType         = "user";
                return(entry);
            }

            if (Computers.Contains(accountType))
            {
                var shortName   = accountName?.TrimEnd('$');
                var dnshostname = result.GetProp("dnshostname");
                if (dnshostname == null)
                {
                    var domain = Utils.ConvertDnToDomain(result.DistinguishedName);
                    dnshostname = $"{shortName}.{domain}".ToUpper();
                }

                entry.IngestCacheDisplay     = dnshostname;
                entry.ObjectType             = "computer";
                entry.ComputerSamAccountName = shortName;
                return(entry);
            }

            if (accountType == null)
            {
                var objClass = result.GetPropArray("objectClass");
                if (objClass.Contains("groupPolicyContainer"))
                {
                    entry.IngestCacheDisplay = $"{result.GetProp("displayname")}@{domainName}";
                    entry.ObjectType         = "gpo";
                    return(entry);
                }

                if (objClass.Contains("organizationalUnit"))
                {
                    entry.IngestCacheDisplay = $"{result.GetProp("name")}@{domainName}";
                    entry.ObjectType         = "ou";
                    return(entry);
                }

                if (objClass.Contains("container"))
                {
                    entry.IngestCacheDisplay = domainName;
                    entry.ObjectType         = "container";
                    return(entry);
                }
            }
            else
            {
                if (accountType.Equals("805306370"))
                {
                    return(null);
                }
            }
            entry.IngestCacheDisplay = domainName;
            entry.ObjectType         = "domain";
            return(entry);
        }
예제 #20
0
        public static IEnumerable <GpoMember> GetGpoMembers(SearchResultEntry entry, string domainName)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.GPOLocalGroup))
            {
                yield break;
            }

            var displayName = entry.GetProp("displayname");
            var name        = entry.GetProp("name");
            var path        = entry.GetProp("gpcfilesyspath");

            if (displayName == null || name == null || path == null)
            {
                yield break;
            }

            var resolvedList = new List <TempGPOStorage>();

            var template = $"{path}\\MACHINE\\Microsoft\\Windows NT\\SecEdit\\GptTmpl.inf";

            if (File.Exists(template))
            {
                var content = File.ReadAllText(template);
                var mMatch  = MemberRegex.Match(content);

                if (mMatch.Success)
                {
                    var memberText = mMatch.Groups[1].Value;
                    var lines      = Regex.Split(memberText.Trim(), @"\r\n|\r|\n");
                    foreach (var line in lines)
                    {
                        var kMatch = KeyRegex.Match(line);

                        var key = kMatch.Groups[1].Value.Trim();
                        var val = kMatch.Groups[2].Value.Trim();

                        var keyMatch = MemberLeftRegex.Match(key);
                        var valMatch = MemberRightRegex.Matches(val);

                        //The first case is when the members of a local group are explicitly set
                        if (keyMatch.Success)
                        {
                            var rid = int.Parse(ExtractRid.Match(keyMatch.Value).Groups[1].Value);
                            foreach (var member in val.Split(','))
                            {
                                var sid = GetSid(member.Trim('*'), domainName);
                                if (sid == null)
                                {
                                    continue;
                                }
                                var obj = _utils.UnknownSidTypeToDisplay(sid, _utils.SidToDomainName(sid), Props);
                                if (obj == null)
                                {
                                    continue;
                                }
                                resolvedList.Add(new TempGPOStorage
                                {
                                    Name = obj.PrincipalName,
                                    RID  = rid,
                                    Type = obj.ObjectType
                                });
                            }
                        }

                        //A group has been set as memberof to one of our rids
                        var index = key.IndexOf("MemberOf", StringComparison.CurrentCultureIgnoreCase);
                        if (valMatch.Count > 0 && index > 0)
                        {
                            var sid = key.Trim('*').Substring(0, index - 3);
                            var obj = _utils.UnknownSidTypeToDisplay(sid, _utils.SidToDomainName(sid), Props);
                            if (obj != null)
                            {
                                foreach (var x in valMatch)
                                {
                                    var rid = int.Parse(ExtractRid.Match(x.ToString()).Groups[1].Value);
                                    resolvedList.Add(new TempGPOStorage
                                    {
                                        Name = obj.PrincipalName,
                                        RID  = rid,
                                        Type = obj.ObjectType
                                    });
                                }
                            }
                        }
                    }
                }
            }

            var xml = $"{path}\\MACHINE\\Preferences\\Groups\\Groups.xml";

            if (File.Exists(xml))
            {
                var doc   = new XPathDocument(xml);
                var nav   = doc.CreateNavigator();
                var nodes = nav.Select("/Groups/Group");

                while (nodes.MoveNext())
                {
                    var properties = nodes.Current.Select("Properties");
                    while (properties.MoveNext())
                    {
                        var groupSid = properties.Current.GetAttribute("groupSid", "");
                        if (groupSid == "")
                        {
                            continue;
                        }

                        if (!groupSid.Equals("S-1-5-32-544"))
                        {
                            continue;
                        }

                        var rid = int.Parse(ExtractRid.Match(groupSid).Groups[1].Value);

                        var members = properties.Current.Select("Members");
                        while (members.MoveNext())
                        {
                            var subMembers = members.Current.Select("Member");
                            while (subMembers.MoveNext())
                            {
                                var action = subMembers.Current.GetAttribute("action", "");
                                if (action.Equals("ADD"))
                                {
                                    var sid = subMembers.Current.GetAttribute("sid", "");
                                    if (string.IsNullOrEmpty(sid))
                                    {
                                        continue;
                                    }
                                    var resolvedPrincipal = _utils.UnknownSidTypeToDisplay(sid, domainName, Props);
                                    if (resolvedPrincipal != null)
                                    {
                                        resolvedList.Add(new TempGPOStorage
                                        {
                                            RID  = rid,
                                            Name = resolvedPrincipal.PrincipalName,
                                            Type = resolvedPrincipal.ObjectType
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }

            var affected = new List <string>();

            if (resolvedList.Count > 0)
            {
                foreach (var ouObject in _utils.DoSearch($"(gplink=*{name}*)", SearchScope.Subtree, GpLinkProps, domainName))
                {
                    var adspath = ouObject.DistinguishedName;

                    foreach (var compEntry in _utils.DoSearch("(objectclass=computer)", SearchScope.Subtree, GpoProps,
                                                              domainName, adspath))
                    {
                        var samAccountType = compEntry.GetProp("samaccounttype");
                        if (samAccountType == null || samAccountType != "805306369")
                        {
                            continue;
                        }

                        var server = compEntry.ResolveAdEntry()?.BloodHoundDisplay;

                        if (server == null)
                        {
                            continue;
                        }

                        affected.Add(server);
                    }
                }
            }

            if (affected.Count > 0)
            {
                var g = new GpoMember
                {
                    AffectedComputers = affected.ToArray(),
                    LocalAdmins       = resolvedList.Where((x) => x.RID == 544).Select((x) => new LocalMember
                    {
                        Name = x.Name,
                        Type = x.Type
                    }).ToArray(),
                    RemoteDesktopUsers = resolvedList.Where((x) => x.RID == 555).Select((x) => new LocalMember
                    {
                        Name = x.Name,
                        Type = x.Type
                    }).ToArray(),
                    DcomUsers = resolvedList.Where((x) => x.RID == 562).Select((x) => new LocalMember
                    {
                        Name = x.Name,
                        Type = x.Type
                    }).ToArray()
                };

                yield return(g);
            }
        }
예제 #21
0
        internal static ResolvedEntry ResolveAdEntry(this SearchResultEntry result)
        {
            var entry = new ResolvedEntry();

            var accountName       = result.GetProp("samaccountname");
            var distinguishedName = result.DistinguishedName;
            var accountType       = result.GetProp("samaccounttype");

            if (distinguishedName == null)
            {
                return(null);
            }

            var domainName = Utils.ConvertDnToDomain(distinguishedName);

            if (Groups.Contains(accountType))
            {
                entry.BloodHoundDisplay = $"{accountName}@{domainName}".ToUpper();
                entry.ObjectType        = "group";
                return(entry);
            }

            if (Users.Contains(accountType))
            {
                entry.BloodHoundDisplay = $"{accountName}@{domainName}".ToUpper();
                entry.ObjectType        = "user";
                return(entry);
            }

            if (Computers.Contains(accountType))
            {
                var shortName   = accountName?.TrimEnd('$');
                var dnshostname = result.GetProp("dnshostname");

                if (dnshostname == null)
                {
                    bool hostFound;
                    if (domainName.Equals(_primaryDomain, StringComparison.CurrentCultureIgnoreCase))
                    {
                        hostFound = DnsManager.HostExistsDns(shortName, out dnshostname);
                        if (!hostFound)
                        {
                            hostFound = DnsManager.HostExistsDns($"{shortName}.{domainName}", out dnshostname);
                        }
                    }
                    else
                    {
                        hostFound = DnsManager.HostExistsDns($"{shortName}.{domainName}", out dnshostname);
                        if (!hostFound)
                        {
                            hostFound = DnsManager.HostExistsDns(shortName, out dnshostname);
                        }
                    }

                    if (!hostFound)
                    {
                        return(null);
                    }
                }
                entry.BloodHoundDisplay      = dnshostname;
                entry.ObjectType             = "computer";
                entry.ComputerSamAccountName = shortName;
                return(entry);
            }



            if (accountType == null)
            {
                var objClass = result.GetPropArray("objectClass");
                if (objClass.Contains("groupPolicyContainer"))
                {
                    entry.BloodHoundDisplay = $"{result.GetProp("displayname")}@{domainName}";
                    entry.ObjectType        = "gpo";
                    return(entry);
                }

                if (objClass.Contains("organizationalUnit"))
                {
                    entry.BloodHoundDisplay = $"{result.GetProp("name")}@{domainName}";
                    entry.ObjectType        = "ou";
                    return(entry);
                }

                if (objClass.Contains("container"))
                {
                    entry.BloodHoundDisplay = domainName;
                    entry.ObjectType        = "container";
                    return(entry);
                }
            }
            else
            {
                if (accountType.Equals("805306370"))
                {
                    return(null);
                }
            }
            entry.BloodHoundDisplay = domainName;
            entry.ObjectType        = "domain";
            return(entry);
        }
예제 #22
0
        public static void GetObjectAces(SearchResultEntry entry, ResolvedEntry resolved, ref Computer g)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ACL))
            {
                return;
            }

            //We only care about computers if they have LAPS installed
            if (entry.GetProp("ms-mcs-admpwdexpirationtime") == null)
            {
                return;
            }

            var aces = new List <ACL>();
            var ntSecurityDescriptor = entry.GetPropBytes("ntsecuritydescriptor");

            //If the ntsecuritydescriptor is null, no point in continuing
            //I'm still not entirely sure what causes this, but it can happen
            if (ntSecurityDescriptor == null)
            {
                return;
            }

            var domainName = Utils.ConvertDnToDomain(entry.DistinguishedName);

            //Convert the ntsecuritydescriptor bytes to a .net object
            var descriptor = new RawSecurityDescriptor(ntSecurityDescriptor, 0);

            //Grab the DACL
            var rawAcl = descriptor.DiscretionaryAcl;
            //Grab the Owner
            var ownerSid = descriptor.Owner.ToString();

            //Determine the owner of the object. Start by checking if we've already determined this is null
            if (!_nullSids.TryGetValue(ownerSid, out _))
            {
                //Check if its a common SID
                if (!MappedPrincipal.GetCommon(ownerSid, out var owner))
                {
                    //Resolve the sid manually if we still dont have it
                    var ownerDomain = _utils.SidToDomainName(ownerSid) ?? domainName;
                    owner = _utils.UnknownSidTypeToDisplay(ownerSid, ownerDomain, Props);
                }
                else
                {
                    owner.PrincipalName = $"{owner.PrincipalName}@{domainName}";
                }

                //Filter out the Local System principal which pretty much every entry has
                if (owner != null && !owner.PrincipalName.Contains("LOCAL SYSTEM") && !owner.PrincipalName.Contains("CREATOR OWNER"))
                {
                    aces.Add(new ACL
                    {
                        AceType       = "",
                        RightName     = "Owner",
                        PrincipalName = owner.PrincipalName,
                        PrincipalType = owner.ObjectType
                    });
                }
                else
                {
                    //We'll cache SIDs we've failed to resolve previously so we dont keep trying
                    _nullSids.TryAdd(ownerSid, new byte());
                }
            }

            foreach (var genericAce in rawAcl)
            {
                var qAce = genericAce as QualifiedAce;
                if (qAce == null)
                {
                    continue;
                }

                var objectSid = qAce.SecurityIdentifier.ToString();
                if (_nullSids.TryGetValue(objectSid, out _))
                {
                    continue;
                }

                //Check if its a common sid
                if (!MappedPrincipal.GetCommon(objectSid, out var mappedPrincipal))
                {
                    //If not common, lets resolve it normally
                    var objectDomain =
                        _utils.SidToDomainName(objectSid) ??
                        domainName;
                    mappedPrincipal = _utils.UnknownSidTypeToDisplay(objectSid, objectDomain, Props);
                    if (mappedPrincipal == null)
                    {
                        _nullSids.TryAdd(objectSid, new byte());
                        continue;
                    }
                }
                else
                {
                    if (mappedPrincipal.PrincipalName == "ENTERPRISE DOMAIN CONTROLLERS")
                    {
                        var dObj = _utils.GetForest(domainName);
                        var d    = dObj == null ? domainName : dObj.RootDomain.Name;
                        mappedPrincipal.PrincipalName = $"{mappedPrincipal.PrincipalName}@{d}".ToUpper();
                    }
                    else
                    {
                        mappedPrincipal.PrincipalName = $"{mappedPrincipal.PrincipalName}@{domainName}".ToUpper();
                    }
                }

                if (mappedPrincipal.PrincipalName.Contains("LOCAL SYSTEM") || mappedPrincipal.PrincipalName.Contains("CREATOR OWNER"))
                {
                    continue;
                }

                //Convert our right to an ActiveDirectoryRight enum object, and then to a string
                var adRight       = (ActiveDirectoryRights)Enum.ToObject(typeof(ActiveDirectoryRights), qAce.AccessMask);
                var adRightString = adRight.ToString();

                //Get the ACE for our right
                var ace  = qAce as ObjectAce;
                var guid = ace != null?ace.ObjectAceType.ToString() : "";

                var inheritedObjectType = ace != null?ace.InheritedObjectAceType.ToString() : "00000000-0000-0000-0000-000000000000";

                var isInherited = inheritedObjectType == "00000000-0000-0000-0000-000000000000" ||
                                  inheritedObjectType == "bf967a86-0de6-11d0-a285-00aa003049e2";

                if (!isInherited && !((ace.AceFlags & AceFlags.InheritOnly) == AceFlags.InheritOnly) && (ace.AceFlags & AceFlags.Inherited) != AceFlags.Inherited)
                {
                    //If these conditions hold the ACE applies to this object anyway
                    isInherited = true;
                }

                if (!isInherited)
                {
                    continue;
                }

                var toContinue = false;


                _guidMap.TryGetValue(guid, out var mappedGuid);

                //Interesting Computer ACEs - GenericAll, WriteDacl, WriteOwner, ExtendedRight
                toContinue |= adRightString.Contains("WriteDacl") ||
                              adRightString.Contains("WriteOwner");

                if (adRightString.Contains("GenericAll"))
                {
                    toContinue |= "00000000-0000-0000-0000-000000000000".Equals(guid) || guid.Equals("") || toContinue;
                    toContinue |= mappedGuid != null && mappedGuid == "ms-Mcs-AdmPwd" || toContinue;
                }

                if (adRightString.Contains("ExtendedRight"))
                {
                    toContinue |= guid.Equals("00000000-0000-0000-0000-000000000000") || guid.Equals("") || toContinue;
                    toContinue |= mappedGuid != null && mappedGuid == "ms-Mcs-AdmPwd" || toContinue;
                }

                if (!toContinue)
                {
                    continue;
                }

                if (adRightString.Contains("GenericAll"))
                {
                    if (mappedGuid == "ms-Mcs-AdmPwd")
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            RightName     = "ReadLAPSPassword"
                        });
                    }
                    else
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            RightName     = "GenericAll"
                        });
                    }
                }

                if (adRightString.Contains("WriteOwner"))
                {
                    aces.Add(new ACL
                    {
                        AceType       = "",
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        RightName     = "WriteOwner"
                    });
                }

                if (adRightString.Contains("WriteDacl"))
                {
                    aces.Add(new ACL
                    {
                        AceType       = "",
                        PrincipalName = mappedPrincipal.PrincipalName,
                        PrincipalType = mappedPrincipal.ObjectType,
                        RightName     = "WriteDacl"
                    });
                }

                if (adRightString.Contains("ExtendedRight"))
                {
                    if (mappedGuid == "ms-Mcs-AdmPwd")
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            RightName     = "ReadLAPSPassword"
                        });
                    }
                    else
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "All",
                            PrincipalName = mappedPrincipal.PrincipalName,
                            PrincipalType = mappedPrincipal.ObjectType,
                            RightName     = "ExtendedRight"
                        });
                    }
                }
            }

            g.Aces = aces.Distinct().ToArray();
        }
예제 #23
0
        public static void GetObjectAces(SearchResultEntry entry, ResolvedEntry resolved, ref Computer obj)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.ACL))
            {
                return;
            }

            var aces = new List <ACL>();
            var ntSecurityDescriptor = entry.GetPropBytes("ntsecuritydescriptor");

            //If the ntsecuritydescriptor is null, no point in continuing
            //I'm still not entirely sure what causes this, but it can happen
            if (ntSecurityDescriptor == null)
            {
                return;
            }

            var domainName = Utils.ConvertDnToDomain(entry.DistinguishedName);

            var newDescriptor = new ActiveDirectorySecurity();

            newDescriptor.SetSecurityDescriptorBinaryForm(ntSecurityDescriptor);
            var owner = GetAclOwner(newDescriptor, domainName);

            if (owner != null)
            {
                aces.Add(new ACL
                {
                    AceType       = "",
                    RightName     = "Owner",
                    PrincipalName = owner.PrincipalName,
                    PrincipalType = owner.ObjectType
                });
            }


            foreach (ActiveDirectoryAccessRule ace in newDescriptor.GetAccessRules(true, true, typeof(SecurityIdentifier)))
            {
                //Ignore null aces
                if (ace == null)
                {
                    continue;
                }

                //Ignore Deny aces
                if (!ace.AccessControlType.Equals(AccessControlType.Allow))
                {
                    continue;
                }

                //Resolve the principal in the ACE
                var principal = GetAcePrincipal(ace, domainName);

                //If its null, we don't care so move on
                if (principal == null)
                {
                    continue;
                }

                //Check if our ACE applies through inheritance rules
                if (!CheckAceInheritanceRules(ace, resolved.ObjectType))
                {
                    continue;
                }

                //Interesting Computer ACEs - GenericAll, WriteDacl, GenericWrite, WriteProperty (AllowedToAct), WriteOwner, ExtendedRight (LAPS)
                var rights        = ace.ActiveDirectoryRights;
                var objectAceType = ace.ObjectType.ToString();

                _guidMap.TryGetValue(objectAceType, out var mappedGuid);

                if (rights.HasFlag(ActiveDirectoryRights.GenericAll))
                {
                    if (objectAceType == AllGuid || objectAceType == "")
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            RightName     = "GenericAll",
                            PrincipalName = principal.PrincipalName,
                            PrincipalType = principal.ObjectType
                        });
                    }
                    else if (mappedGuid != null && mappedGuid == "ms-Mcs-AdmPwd")
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            RightName     = "ReadLAPSPassword",
                            PrincipalName = principal.PrincipalName,
                            PrincipalType = principal.ObjectType
                        });
                    }
                    //GenericAll includes every other flag, so continue here so we don't duplicate privs
                    continue;
                }

                if (rights.HasFlag(ActiveDirectoryRights.GenericWrite) ||
                    rights.HasFlag(ActiveDirectoryRights.WriteProperty))
                {
                    //GenericWrite encapsulates WriteProperty
                    if (rights.HasFlag(ActiveDirectoryRights.GenericWrite) &&
                        (objectAceType == AllGuid || objectAceType == ""))
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            RightName     = "GenericWrite",
                            PrincipalName = principal.PrincipalName,
                            PrincipalType = principal.ObjectType
                        });
                    }
                    else if (rights.HasFlag(ActiveDirectoryRights.WriteProperty))
                    {
                        if (objectAceType == AllGuid || objectAceType == "")
                        {
                            aces.Add(new ACL
                            {
                                AceType       = "",
                                RightName     = "GenericWrite",
                                PrincipalName = principal.PrincipalName,
                                PrincipalType = principal.ObjectType
                            });
                        }
                        else if (objectAceType == "3f78c3e5-f79a-46bd-a0b8-9d18116ddc79")
                        {
                            aces.Add(new ACL
                            {
                                AceType       = "AllowedToAct",
                                PrincipalName = principal.PrincipalName,
                                PrincipalType = principal.ObjectType,
                                RightName     = "WriteProperty"
                            });
                        }
                    }
                }

                if (rights.HasFlag(ActiveDirectoryRights.WriteDacl))
                {
                    aces.Add(new ACL
                    {
                        AceType       = "",
                        RightName     = "WriteDacl",
                        PrincipalName = principal.PrincipalName,
                        PrincipalType = principal.ObjectType
                    });
                }

                if (rights.HasFlag(ActiveDirectoryRights.WriteOwner))
                {
                    aces.Add(new ACL
                    {
                        AceType       = "",
                        RightName     = "WriteOwner",
                        PrincipalName = principal.PrincipalName,
                        PrincipalType = principal.ObjectType
                    });
                }

                if (rights.HasFlag(ActiveDirectoryRights.ExtendedRight))
                {
                    if (mappedGuid != null && mappedGuid == "ms-Mcs-AdmPwd" && entry.GetProp("ms-mcs-admpwdexpirationtime") != null)
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "",
                            RightName     = "ReadLAPSPassword",
                            PrincipalName = principal.PrincipalName,
                            PrincipalType = principal.ObjectType
                        });
                    }
                    else if (objectAceType == AllGuid || objectAceType == "")
                    {
                        aces.Add(new ACL
                        {
                            AceType       = "All",
                            RightName     = "ExtendedRight",
                            PrincipalName = principal.PrincipalName,
                            PrincipalType = principal.ObjectType
                        });
                    }
                }
            }

            obj.Aces = aces.Distinct().ToArray();
        }
예제 #24
0
        /// <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
                       }
            }
            ;
        }