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")); }
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); }
private static IEnumerable <string> GetNetLoggedOn(ResolvedEntry entry, string computerDomain) { var users = new List <string>(); const int queryLevel = 1; var resumeHandle = 0; var tWui1 = typeof(WKSTA_USER_INFO_1); //Call the API to get logged on users var result = NetWkstaUserEnum(entry.IngestCacheDisplay, queryLevel, out IntPtr intPtr, -1, out int entriesRead, out int _, ref resumeHandle); //If we don't get 0 or 234 return if (result != 0 && result != 234) { yield break; } var iter = intPtr; for (var i = 0; i < entriesRead; i++) { var data = (WKSTA_USER_INFO_1)Marshal.PtrToStructure(iter, tWui1); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(tWui1)); var domain = data.wkui1_logon_domain; var username = data.wkui1_username; if (domain.Equals(entry.ComputerSamAccountName, StringComparison.CurrentCultureIgnoreCase) || username.Trim().Equals("") || username.EndsWith("$", StringComparison.Ordinal)) { continue; } //Try to convert the domain part to a FQDN, if it doesn't work just use the computer's domain var domainName = _utils.DomainNetbiosToFqdn(domain) ?? computerDomain; users.Add($"{username}@{domainName}".ToUpper()); } NetApiBufferFree(intPtr); foreach (var user in users.Distinct()) { yield return(user); } }
internal static IEnumerable <Session> DoLoggedOnCollection(ResolvedEntry target, string domainName) { if (!Utils.IsMethodSet(ResolvedCollectionMethod.LoggedOn) && !Utils.IsMethodSet(ResolvedCollectionMethod.LoggedOnLoop)) { yield break; } var t = Task <List <string> > .Factory.StartNew(() => { var users = new List <string>(); users.AddRange(GetRegistryLoggedOn(target)); users.AddRange(GetNetLoggedOn(target, domainName)); return(users); }); var success = t.Wait(Timeout); if (!success) { throw new TimeoutException(); } var sessions = new List <Session>(); foreach (var u in t.Result.Distinct()) { sessions.Add(new Session { ComputerName = target.IngestCacheDisplay, UserName = u, Weight = 1 }); } foreach (var x in sessions) { yield return(x); } Utils.DoJitter(); }
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; }
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")); }
//internal static void DoLoggedOnCollection(ResolvedEntry target, string domainName, ref Computer obj) //{ // if (!Utils.IsMethodSet(ResolvedCollectionMethod.LoggedOn)) // return; // var users = new List<string>(); // users.AddRange(GetRegistryLoggedOn(target)); // users.AddRange(GetNetLoggedOn(target, domainName)); // var sessions = new List<Session>(); // foreach (var u in users.Distinct()) // { // sessions.Add(new Session // { // ComputerName = target.IngestCacheDisplay, // UserName = u, // Weight = 1 // }); // } // if (sessions.Count > 0) // obj.Sessions = sessions.ToArray(); //} private static IEnumerable <string> GetRegistryLoggedOn(ResolvedEntry target) { var users = new List <string>(); try { //Remotely open the registry hive if its not our current one var key = RegistryKey.OpenRemoteBaseKey(RegistryHive.Users, Environment.MachineName.Equals(target.ComputerSamAccountName, StringComparison.CurrentCultureIgnoreCase) ? "" : target.IngestCacheDisplay); //Find all the subkeys that match our regex var filtered = key.GetSubKeyNames() .Where(sub => SidRegex.IsMatch(sub)); foreach (var subkey in filtered) { //Convert our sid to a username var user = _utils.SidToDisplay(subkey, _utils.SidToDomainName(subkey), RegistryProps, "user"); if (user == null) { continue; } users.Add(user.ToUpper()); } } catch (Exception) { yield break; } foreach (var user in users.Distinct()) { yield return(user); } }
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(); }
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).ToUpper(); 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.IngestCacheDisplay); } else { users.Add(subResolved.IngestCacheDisplay); } } obj.Users = users.ToArray(); obj.Computers = computers.ToArray(); obj.ChildOus = ous.ToArray(); }
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 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 (entry.GetProp("ms-mcs-admpwdexpirationtime") != null) { if (mappedGuid != null && mappedGuid == "ms-Mcs-AdmPwd") { 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(); }
public static void GetObjectAces(SearchResultEntry entry, ResolvedEntry resolved, ref Domain 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 Domain ACEs - GenericAll, WriteDacl, WriteOwner, Replication Rights, AllExtendedRights var rights = ace.ActiveDirectoryRights; var objectAceType = ace.ObjectType.ToString(); if (rights.HasFlag(ActiveDirectoryRights.GenericAll)) { if (objectAceType == AllGuid || objectAceType == "") { aces.Add(new ACL { AceType = "", RightName = "GenericAll", 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.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 (objectAceType == "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2") { aces.Add(new ACL { AceType = "GetChanges", RightName = "ExtendedRight", PrincipalName = principal.PrincipalName, PrincipalType = principal.ObjectType }); } else if (objectAceType == "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2") { aces.Add(new ACL { AceType = "GetChangesAll", RightName = "ExtendedRight", 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(); }
public static IEnumerable <Session> GetNetSessions(ResolvedEntry target, string computerDomain) { if (!Utils.IsMethodSet(ResolvedCollectionMethod.Session) && !Utils.IsMethodSet(ResolvedCollectionMethod.SessionLoop)) { yield break; } Utils.Debug($"Starting NetSessionEnum for {target.IngestCacheDisplay}"); var resumeHandle = IntPtr.Zero; var si10 = typeof(SESSION_INFO_10); var entriesRead = 0; var ptrInfo = IntPtr.Zero; var t = Task <int> .Factory.StartNew(() => NetSessionEnum(target.IngestCacheDisplay, null, null, 10, out ptrInfo, -1, out entriesRead, out _, ref resumeHandle)); var success = t.Wait(Timeout); if (!success) { throw new TimeoutException(); } var returnValue = t.Result; Utils.Debug($"EntriesRead from NetSessionEnum: {entriesRead}"); Utils.Debug($"ReturnValue from NetSessionEnum: {returnValue}"); //If we don't get a success, just break if (returnValue != (int)NERR.NERR_Success) { yield break; } var results = new SESSION_INFO_10[entriesRead]; var iter = ptrInfo; //Loop over the data and store it into an array for (var i = 0; i < entriesRead; i++) { results[i] = (SESSION_INFO_10)Marshal.PtrToStructure(iter, si10); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(si10)); } //Free the IntPtr NetApiBufferFree(ptrInfo); foreach (var result in results) { var username = result.sesi10_username; var cname = result.sesi10_cname; if (cname == null || username.EndsWith("$") || username.Trim() == "" || username == "$" || username == _options.CurrentUser || username == "ANONYMOUS LOGON") { continue; } if (cname.StartsWith("\\", StringComparison.CurrentCulture)) { cname = cname.TrimStart('\\'); } if (cname.Equals("[::1]") || cname.Equals("127.0.0.1")) { cname = target.IngestCacheDisplay; } Utils.Debug($"Result Username: {username}"); Utils.Debug($"Original cname: {cname}"); var watch = Stopwatch.StartNew(); var dnsHostName = _utils.ResolveCname(cname, computerDomain).Replace("\\", ""); watch.Stop(); Utils.Debug($"Name resolution took {watch.ElapsedMilliseconds}"); Utils.Debug($"Result cname: {dnsHostName}"); //If we're skipping Global Catalog deconfliction, just return a session if (_options.SkipGcDeconfliction) { yield return(new Session { ComputerName = dnsHostName, UserName = username, Weight = 2 }); } else { //Check our cache first if (!_cache.GetGcMap(username.ToUpper(), out var possible)) { Utils.Debug($"Missed cache hit for {username}"); //If we didn't get a cache hit, search the global catalog var temp = new List <string>(); foreach (var entry in _utils.DoSearch( $"(&(samAccountType=805306368)(samaccountname={username}))", SearchScope.Subtree, new[] { "distinguishedname" }, useGc: true)) { temp.Add(Utils.ConvertDnToDomain(entry.DistinguishedName).ToUpper()); } possible = temp.ToArray(); _cache.AddGcMap(username.ToUpper(), possible); } else { Utils.Debug($"Cache hit for {username}"); if (possible == null) { possible = new string[0]; } } switch (possible.Length) { case 0: //Object isn't in GC, so we'll default to the computer's domain yield return(new Session { UserName = $"{username}@{computerDomain}", ComputerName = dnsHostName, Weight = 2 }); break; case 1: //Exactly one instance of this samaccountname, the best scenario yield return(new Session { UserName = $"{username}@{possible.First()}", ComputerName = dnsHostName, Weight = 2 }); break; default: //Multiple possibilities (whyyyyy) //Add a weight of 1 for same domain as computer, 2 for others foreach (var possibility in possible) { var weight = possibility.Equals(computerDomain, StringComparison.CurrentCultureIgnoreCase) ? 1 : 2; yield return(new Session { Weight = weight, ComputerName = dnsHostName.ToUpper(), UserName = $"{username}@{possibility}" }); } break; } } } Utils.DoJitter(); }
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")); }
private static SamEnumerationObject[] NetLocalGroupGetMembers(ResolvedEntry entry, int rid, out string machineSid) { Utils.Debug("Starting NetLocalGroupGetMembers"); var server = new UNICODE_STRING(entry.IngestCacheDisplay); //Connect to the server with the proper access maskes. This gives us our server handle var obj = default(OBJECT_ATTRIBUTES); Utils.Debug("Starting SamConnect"); var status = SamConnect(ref server, out var serverHandle, SamAccessMasks.SamServerLookupDomain | SamAccessMasks.SamServerConnect, ref obj); Utils.Debug($"SamConnect returned {status}"); switch (status) { case NtStatus.StatusRpcServerUnavailable: throw new SystemDownException(); case NtStatus.StatusSuccess: break; default: throw new ApiFailedException(); } Utils.Debug("Starting SamLookupDomainInSamServer"); //Use SamLookupDomainInServer with the hostname to find the machine sid if possible try { var san = new UNICODE_STRING(entry.ComputerSamAccountName); SamLookupDomainInSamServer(serverHandle, ref san, out var temp); //This will throw an exception if we didn't actually find the alias machineSid = new SecurityIdentifier(temp).Value; SamFreeMemory(temp); } catch { machineSid = "DUMMYSTRINGSHOULDNOTMATCH"; } Utils.Debug($"Resolved Machine Sid {machineSid}"); Utils.Debug("Starting SamOpenDomain"); //Open the domain for the S-1-5-32 (BUILTIN) alias status = SamOpenDomain(serverHandle, DomainAccessMask.Lookup, _sidbytes, out var domainHandle); Utils.Debug($"SamOpenDomain returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug("Starting SamOpenAlias"); //Open the alias for the desired RID status = SamOpenAlias(domainHandle, AliasOpenFlags.ListMembers, rid, out var aliasHandle); Utils.Debug($"SamOpenAlias returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug("Starting SamGetMembersInAlias"); //Get the members in the alias. This returns a list of SIDs status = SamGetMembersInAlias(aliasHandle, out var members, out var count); Utils.Debug($"SamGetMembersInAlias returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(aliasHandle); SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug("Cleaning up handles"); SamCloseHandle(aliasHandle); SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); if (count == 0) { SamFreeMemory(members); return(new SamEnumerationObject[0]); } Utils.Debug("Copying data"); //Copy the data of our sids to a new array so it doesn't get eaten var grabbedSids = new IntPtr[count]; Marshal.Copy(members, grabbedSids, 0, count); var sids = new string[count]; //Convert the bytes to strings for usage for (var i = 0; i < count; i++) { try { sids[i] = new SecurityIdentifier(grabbedSids[i]).Value; } catch { sids[i] = null; } } Utils.Debug("Starting LsaOpenPolicy"); //Open the LSA policy on the target machine var obja = default(OBJECT_ATTRIBUTES); status = LsaOpenPolicy(ref server, ref obja, LsaOpenMask.ViewLocalInfo | LsaOpenMask.LookupNames, out var policyHandle); Utils.Debug($"LSAOpenPolicy returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { LsaClose(policyHandle); SamFreeMemory(members); throw new ApiFailedException(); } Utils.Debug("Starting LSALookupSids"); var nameList = IntPtr.Zero; var domainList = IntPtr.Zero; //Call LsaLookupSids using the sids we got from SamGetMembersInAlias status = LsaLookupSids(policyHandle, count, members, ref domainList, ref nameList); Utils.Debug($"LSALookupSids returned {status}"); if (!status.Equals(NtStatus.StatusSuccess) && !status.Equals(NtStatus.StatusSomeMapped)) { LsaClose(policyHandle); LsaFreeMemory(domainList); LsaFreeMemory(nameList); SamFreeMemory(members); throw new ApiFailedException(); } Utils.Debug("Finished API calls"); //Convert the returned names into structures var iter = nameList; var translatedNames = new LsaTranslatedNames[count]; Utils.Debug("Resolving names"); for (var i = 0; i < count; i++) { translatedNames[i] = (LsaTranslatedNames)Marshal.PtrToStructure(iter, typeof(LsaTranslatedNames)); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(typeof(LsaTranslatedNames))); } Utils.Debug("Resolving domains"); //Convert the returned domain list to a structure var lsaDomainList = (LsaReferencedDomainList)(Marshal.PtrToStructure(domainList, typeof(LsaReferencedDomainList))); //Convert the domain list to individual structures var trustInfos = new LsaTrustInformation[lsaDomainList.count]; iter = lsaDomainList.domains; for (var i = 0; i < lsaDomainList.count; i++) { trustInfos[i] = (LsaTrustInformation)Marshal.PtrToStructure(iter, typeof(LsaTrustInformation)); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(typeof(LsaTrustInformation))); } Utils.Debug("Matching up data"); var resolvedObjects = new SamEnumerationObject[translatedNames.Length]; //Match up sids, domain names, and account names for (var i = 0; i < translatedNames.Length; i++) { var x = translatedNames[i]; if (x.DomainIndex > trustInfos.Length || x.DomainIndex < 0 || trustInfos.Length == 0) { continue; } resolvedObjects[i] = new SamEnumerationObject { AccountDomain = trustInfos[x.DomainIndex].name.ToString(), AccountName = x.Name.ToString(), AccountSid = sids[i], SidUsage = x.Use }; } Utils.Debug("Cleaning up"); //Cleanup SamFreeMemory(members); LsaFreeMemory(domainList); LsaFreeMemory(nameList); LsaClose(policyHandle); Utils.Debug("Done NetLocalGroupGetMembers"); return(resolvedObjects); }
internal static void DoTrustEnumeration(ResolvedEntry resolved, ref Domain obj) { if (!Utils.IsMethodSet(ResolvedCollectionMethod.Trusts)) { return; } if (resolved == null) { return; } var trusts = new List <Trust>(); var dc = _utils.GetUsableDomainController(_utils.GetDomain(resolved.IngestCacheDisplay)); //var dc = _utils // .DoSearch("(userAccountControl:1.2.840.113556.1.4.803:=8192)", SearchScope.Subtree, // new[] { "dnshostname" }, resolved.IngestCacheDisplay).DefaultIfEmpty(null).FirstOrDefault(); if (dc == null) { return; } const uint flags = 63; var ddt = typeof(DsDomainTrusts); var result = DsEnumerateDomainTrusts(dc, flags, out var ptr, out var domainCount); if (result != 0) { return; } var array = new DsDomainTrusts[domainCount]; var iter = ptr; //Loop over the data and store it in an array for (var i = 0; i < domainCount; i++) { array[i] = (DsDomainTrusts)Marshal.PtrToStructure(iter, ddt); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(ddt)); } NetApiBufferFree(ptr); for (var i = 0; i < domainCount; i++) { var trust = new Trust(); var data = array[i]; var trustFlags = (TrustFlags)data.Flags; var trustAttribs = (TrustAttrib)data.TrustAttributes; // the domain itself if ((trustFlags & TrustFlags.DsDomainPrimary) == TrustFlags.DsDomainPrimary) { continue; } if (data.DnsDomainName == null) { continue; } trust.TargetName = data.DnsDomainName; var inbound = (trustFlags & TrustFlags.DsDomainDirectInbound) == TrustFlags.DsDomainDirectInbound; var outbound = (trustFlags & TrustFlags.DsDomainDirectOutbound) == TrustFlags.DsDomainDirectOutbound; if (inbound && outbound) { trust.TrustDirection = (int)TrustDirection.Bidirectional; } else if (inbound) { trust.TrustDirection = (int)TrustDirection.Inbound; } else if (outbound) { trust.TrustDirection = (int)TrustDirection.Outbound; } else { // a trust with no direction is probably not enabled (According to MS documentation) // see: https://docs.microsoft.com/fr-fr/windows/desktop/api/ntsecapi/ns-ntsecapi-_trusted_domain_information_ex (TrustDirection) continue; } // parentChild occure only when one of the domain is the forest root // Check is trusted domain is the current forest root or if trusted domain's parent is current enumerated domain if (((trustFlags & TrustFlags.DsDomainTreeRoot) == TrustFlags.DsDomainTreeRoot) && ((trustFlags & TrustFlags.DsDomainInForest) == TrustFlags.DsDomainInForest) || array[data.ParentIndex].DnsDomainName.ToUpper() == resolved.IngestCacheDisplay) { trust.TrustType = "ParentChild"; } else if ((trustFlags & TrustFlags.DsDomainInForest) == TrustFlags.DsDomainInForest) { trust.TrustType = "CrossLink"; } else if ((trustAttribs & TrustAttrib.ForestTransitive) == TrustAttrib.ForestTransitive) { trust.TrustType = "Forest"; } else { trust.TrustType = "External"; } if ((trustAttribs & TrustAttrib.NonTransitive) == TrustAttrib.NonTransitive) { trust.IsTransitive = false; } else { trust.IsTransitive = true; } trusts.Add(trust); } obj.Trusts = trusts.ToArray(); }
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, sensitive, dontReqPreAuth, passwdNotReq, unconstrained; if (int.TryParse(uac, out var flag)) { var flags = (UacFlags)flag; enabled = (flags & UacFlags.AccountDisable) == 0; trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0; sensitive = (flags & UacFlags.NotDelegated) != 0; dontReqPreAuth = (flags & UacFlags.DontReqPreauth) != 0; passwdNotReq = (flags & UacFlags.PasswordNotRequired) != 0; unconstrained = (flags & UacFlags.TrustedForDelegation) != 0; } else { trustedToAuth = false; enabled = true; sensitive = false; dontReqPreAuth = false; passwdNotReq = false; unconstrained = 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(); 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("lastlogontimestamp", ConvertToUnixEpoch(entry.GetProp("lastlogontimestamp"))); 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")); obj.Properties.Add("sensitive", sensitive); obj.Properties.Add("dontreqpreauth", dontReqPreAuth); obj.Properties.Add("passwordnotreqd", passwdNotReq); obj.Properties.Add("unconstraineddelegation", unconstrained); 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); } }