private static MappedPrincipal GetAclOwner(ActiveDirectorySecurity acl, string domainName) { var sid = acl.GetOwner(typeof(SecurityIdentifier)).Value; //Filter Local System/Creator Owner/Principal Self if (sid == "S-1-5-18" || sid == "S-1-3-0" || sid == "S-1-5-10") { return(null); } if (!_nullSids.TryGetValue(sid, out _)) { //Check if its a common SID if (!MappedPrincipal.GetCommon(sid, out var owner)) { //Resolve the sid manually if we still dont have it var ownerDomain = _utils.SidToDomainName(sid) ?? domainName; owner = _utils.UnknownSidTypeToDisplay(sid, ownerDomain, Props); } else { owner.PrincipalName = $"{owner.PrincipalName}@{domainName}"; } //We'll cache SIDs we've failed to resolve previously so we dont keep trying if (owner == null) { _nullSids.TryAdd(sid, new byte()); } return(owner); } return(null); }
private static MappedPrincipal GetAcePrincipal(ActiveDirectoryAccessRule rule, string domainName) { var sid = rule.IdentityReference.Value; //Filter Local System/Creator Owner/Principal Self if (sid == "S-1-5-18" || sid == "S-1-3-0" || sid == "S-1-5-10") { return(null); } if (!_nullSids.TryGetValue(sid, out _)) { //Check if its a common SID if (!MappedPrincipal.GetCommon(sid, out var principal)) { //Resolve the sid manually if we still don't have it var ownerDomain = _utils.SidToDomainName(sid) ?? domainName; principal = _utils.UnknownSidTypeToDisplay(sid, ownerDomain, Props); } else { if (sid == "S-1-5-9") { var dObj = _utils.GetForest(domainName); var d = dObj == null ? domainName : dObj.RootDomain.Name; principal.PrincipalName = $"ENTERPRISE DOMAIN CONTROLLERS@{d}".ToUpper(); } else { principal.PrincipalName = $"{principal.PrincipalName}@{domainName}"; } } //We'll cache SIDs we've failed to resolve previously so we dont keep trying if (principal == null) { _nullSids.TryAdd(sid, new byte()); } return(principal); } return(null); }
public static IEnumerable <LocalMember> GetGroupMembers(ResolvedEntry entry, LocalGroupRids rid) { if (rid.Equals(LocalGroupRids.Administrators) && !Utils.IsMethodSet(ResolvedCollectionMethod.LocalAdmin)) { yield break; } if (rid.Equals(LocalGroupRids.RemoteDesktopUsers) && !Utils.IsMethodSet(ResolvedCollectionMethod.RDP)) { yield break; } if (rid.Equals(LocalGroupRids.DcomUsers) && !Utils.IsMethodSet(ResolvedCollectionMethod.DCOM)) { yield break; } Utils.Debug("Starting GetSamAdmins"); string machineSid = null; Utils.Debug("Starting Task"); var t = Task <SamEnumerationObject[]> .Factory.StartNew(() => { try { return(NetLocalGroupGetMembers(entry, (int)rid, out machineSid)); } catch (ApiFailedException) { return(new SamEnumerationObject[0]); } catch (SystemDownException) { return(new SamEnumerationObject[0]); } }); var success = t.Wait(Timeout); Utils.Debug("Task Finished"); if (!success) { Utils.Debug("SamAdmin Timeout"); throw new TimeoutException(); } Utils.Debug("SamAdmin success"); var resolvedObjects = t.Result; if (resolvedObjects.Length == 0) { Utils.Debug("SamAdmins returned 0 objects"); yield break; } Utils.Debug("Processing data"); //Process our list of stuff now foreach (var data in resolvedObjects) { var sid = data?.AccountSid; Utils.Debug($"Processing sid: {sid}"); if (sid == null) { Utils.Debug("Null sid"); continue; } if (data.AccountName.Equals(string.Empty)) { Utils.Debug("Empty AccountName"); continue; } if (sid.StartsWith(machineSid)) { Utils.Debug("Local Account"); continue; } string type; switch (data.SidUsage) { case SidNameUse.SidTypeUser: type = "user"; break; case SidNameUse.SidTypeGroup: type = "group"; break; case SidNameUse.SidTypeComputer: type = "computer"; break; case SidNameUse.SidTypeWellKnownGroup: type = "wellknown"; break; case SidNameUse.SidTypeAlias: type = "group"; break; default: type = null; break; } if (type == null) { continue; } if (data.AccountName.EndsWith("$")) { type = "unknown"; } string resolvedName; Utils.Debug($"Object Type: {type}"); if (type.Equals("unknown")) { Utils.Debug("Resolving Sid to object UnknownType"); var mp = _utils.UnknownSidTypeToDisplay(sid, _utils.SidToDomainName(sid), AdminProps); if (mp == null) { continue; } Utils.Debug($"Got Object: {mp.PrincipalName}"); resolvedName = mp.PrincipalName; type = mp.ObjectType; } else if (type == "wellknown") { if (MappedPrincipal.GetCommon(sid, out var result)) { if (result.PrincipalName.Equals("Local System")) { continue; } string domain; try { var split = string.Join(".", entry.IngestCacheDisplay.Split('.').Skip(1).ToArray()); domain = split; } catch { domain = _utils.GetDomain(_options.Domain).Name; } type = result.ObjectType; resolvedName = $"{result.PrincipalName}@{domain}".ToUpper(); } else { continue; } } else { Utils.Debug("Resolving Sid to Object"); resolvedName = _utils.SidToDisplay(sid, _utils.SidToDomainName(sid), AdminProps, type); if (resolvedName == null) { continue; } Utils.Debug($"Got Object: {resolvedName}"); } yield return(new LocalMember { Type = type, Name = resolvedName }); } Utils.DoJitter(); }
public static void GetObjectAces(SearchResultEntry entry, ResolvedEntry resolved, ref Ou g) { 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); //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 flags = ace == null ? AceFlags.None : ace.AceFlags; var isInherited = (flags & AceFlags.InheritOnly) != 0; isInherited = isInherited && (inheritedObjectType == "00000000-0000-0000-0000-000000000000" || inheritedObjectType == "bf967aa5-0de6-11d0-a285-00aa003049e2"); //Special case used for example by Exchange: the ACE is inherited but also applies to the object it is set on // this is verified by looking if this ACE is not inherited, and is not an inherit-only ACE if (!isInherited && (flags & AceFlags.InheritOnly) != AceFlags.InheritOnly && (flags & 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 OU ACEs - GenericAll, GenericWrite, WriteDacl, WriteOwner, toContinue |= adRightString.Contains("WriteDacl") || adRightString.Contains("WriteOwner"); if (adRightString.Contains("GenericAll")) { toContinue |= "00000000-0000-0000-0000-000000000000".Equals(guid) || guid.Equals("") || toContinue; } if (adRightString.Contains("WriteProperty")) { toContinue |= guid.Equals("00000000-0000-0000-0000-000000000000") || guid.Equals("f30e3bbe-9ff0-11d1-b603-0000f80367c1") || guid.Equals("") || 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(); }
public static void GetGroupInfo(SearchResultEntry entry, ResolvedEntry resolved, string domainSid, ref Group u) { if (!Utils.IsMethodSet(ResolvedCollectionMethod.Group)) { return; } var fMembers = new List <GroupMember>(); var principalDisplayName = resolved.IngestCacheDisplay; var principalDomainName = Utils.ConvertDnToDomain(entry.DistinguishedName); if (resolved.ObjectType == "group") { _cache.AddMapValue(entry.DistinguishedName, "group", principalDisplayName); } var members = entry.GetPropArray("member"); if (members.Length == 0) { var tempMembers = new List <string>(); var bottom = 0; while (true) { var top = bottom + 1499; var range = $"member;range={bottom}-{top}"; bottom += 1500; //Try ranged retrieval var result = _utils.DoSearch("(objectclass=*)", SearchScope.Base, new[] { range }, principalDomainName, entry.DistinguishedName).DefaultIfEmpty(null).FirstOrDefault(); //We didn't get an object back. Break out of the loop if (result?.Attributes.AttributeNames == null) { break; } var en = result.Attributes.AttributeNames.GetEnumerator(); //If the enumerator fails, that means theres really no members at all if (!en.MoveNext()) { break; } if (en.Current == null) { continue; } var attrib = en.Current.ToString(); if (attrib.EndsWith("-*")) { //We're done here, no more members to grab break; } tempMembers.AddRange(result.GetPropArray(attrib)); } members = tempMembers.ToArray(); } foreach (var dn in members) { //Check our cache first if (!_cache.GetMapValueUnknownType(dn, out var principal)) { if (dn.Contains("ForeignSecurityPrincipals")) { var sid = dn.Split(',')[0].Substring(3); if (dn.Contains("CN=S-1-5-21")) { var domain = _utils.SidToDomainName(sid); if (domain == null) { Utils.Verbose($"Unable to resolve domain for FSP {dn}"); continue; } principal = _utils.UnknownSidTypeToDisplay(sid, domain, Props); } else { if (!MappedPrincipal.GetCommon(sid, out principal)) { continue; } principal.PrincipalName = $"{principal.PrincipalName}@{principalDomainName}"; } } else { var objEntry = _utils .DoSearch("(objectclass=*)", SearchScope.Base, Props, Utils.ConvertDnToDomain(dn), dn) .DefaultIfEmpty(null).FirstOrDefault(); if (objEntry == null) { principal = null; } else { var resolvedObj = objEntry.ResolveAdEntry(); if (resolvedObj == null || resolvedObj.ObjectType == "domain") { principal = null; } else { _cache.AddMapValue(dn, resolvedObj.ObjectType, resolvedObj.IngestCacheDisplay); principal = new MappedPrincipal ( resolvedObj.IngestCacheDisplay, resolvedObj.ObjectType ); } } } } if (principal != null) { fMembers.Add(new GroupMember { MemberName = principal.PrincipalName, MemberType = principal.ObjectType }); } } u.Members = fMembers.Distinct().ToArray(); }
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, Utils.ConvertDnToDomain(entry.DistinguishedName)); 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")); }