public void SetDomainUsers() { DirectorySearch ds = GetDirectorySearcher(); List <string> domainUsers = new List <string>(); string[] ldapProperties = new string[] { "name", "adminCount", "sAMAccountName", "userAccountControl", "servicePrincipalName", "userPrincipalName" }; string ldapFilter = "(&(objectClass=user)(objectCategory=person))"; IEnumerable <SearchResultEntry> searchResultEntries = ds.QueryLdap(ldapFilter, ldapProperties, System.DirectoryServices.Protocols.SearchScope.Subtree); foreach (SearchResultEntry resEnt in searchResultEntries) { bool keepUser = false; try { //busted account name if (String.IsNullOrEmpty(resEnt.GetProperty("sAMAccountName"))) { continue; } int uacFlags; bool success = int.TryParse(resEnt.GetProperty("userAccountControl"), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } string userName = resEnt.GetProperty("sAMAccountName"); if (userName.EndsWith("$")) { Mq.Trace("Skipping " + userName + " because it appears to be a computer or trust account."); continue; } //skip mailboxy accounts - domains always have a billion of these. if (userName.IndexOf("mailbox", StringComparison.OrdinalIgnoreCase) >= 0) { Mq.Trace("Skipping " + userName + " because it appears to be a mailbox."); continue; } if (userName.IndexOf("mbx", StringComparison.OrdinalIgnoreCase) >= 0) { Mq.Trace("Skipping " + userName + " because it appears to be a mailbox."); continue; } // if has an SPN, keep it if (!keepUser && resEnt.GetProperty("servicePrincipalName") != null) { Mq.Trace("Adding " + userName + " to target list because it has an SPN"); keepUser = true; } // if it's got adminCount, keep it if (!keepUser && resEnt.GetProperty("adminCount") == "1") { Mq.Trace("Adding " + userName + " to target list because it had adminCount=1."); keepUser = true; } // if the password doesn't expire it's probably a service account if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.PasswordDoesNotExpire)) { Mq.Trace("Adding " + userName + " to target list because password does not expire, probably service account."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.DontRequirePreauth)) { Mq.Trace("Adding " + userName + " to target list because it doesn't require Kerberos pre-auth."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.TrustedForDelegation)) { Mq.Trace("Adding " + userName + " to target list because it is trusted for delegation."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags .TrustedToAuthenticateForDelegation)) { Mq.Trace("Adding " + userName + " to target list because it is trusted for delegation."); keepUser = true; } // Included patterns if (!keepUser) { foreach (string str in MyOptions.DomainUserMatchStrings) { if (userName.ToLower().Contains(str.ToLower())) { Mq.Trace("Adding " + userName + " to target list because it contained " + str + "."); keepUser = true; break; } } } // Finished testing if (!keepUser) { continue; } // Must have matched something // For common/frequent names, force fully-qualified strict formats if (MyOptions.DomainUserStrictStrings.Contains(userName, StringComparer.OrdinalIgnoreCase)) { Mq.Trace("Using strict formats for " + userName + "."); domainUsers.Add(String.Format(@"{0}\{1}", _targetDomainNetBIOSName, userName)); if (!string.IsNullOrEmpty(resEnt.GetProperty("userPrincipalName"))) { domainUsers.Add(resEnt.GetProperty("userPrincipalName")); } continue; } // Otherwise, go with the format preference from the config file foreach (DomainUserNamesFormat dnuf in MyOptions.DomainUserNameFormats) { switch (dnuf) { case DomainUserNamesFormat.NetBIOS: domainUsers.Add(String.Format(@"{0}\{1}", _targetDomainNetBIOSName, userName)); break; case DomainUserNamesFormat.UPN: if (!string.IsNullOrEmpty(resEnt.GetProperty("userPrincipalName"))) { domainUsers.Add(resEnt.GetProperty("userPrincipalName")); } else { Mq.Trace("Adding " + userName + " with simple sAMAccountName because UPN is missing."); domainUsers.Add(userName); } break; case DomainUserNamesFormat.sAMAccountName: domainUsers.Add(userName); break; } } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } this._domainUsers = domainUsers; }
private void SetDomainUsersAndComputers() { if (!String.IsNullOrEmpty(MyOptions.TargetDc)) { DomainControllers.Add(MyOptions.TargetDc); } else { GetDomainControllers(); } List <string> domainComputers = new List <string>(); List <string> domainUsers = new List <string>(); // we do this so if the first one fails we keep trying til we find a DC we can talk to. foreach (string domainController in DomainControllers) { try { // TODO add support for user defined creds here. using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainController)) { using (DirectorySearcher mySearcher = new DirectorySearcher(entry)) { mySearcher.Filter = ("(objectClass=computer)"); // No size limit, reads all objects mySearcher.SizeLimit = 0; // Read data in pages of 250 objects. Make sure this value is below the limit configured in your AD domain (if there is a limit) mySearcher.PageSize = 250; // Let searcher know which properties are going to be used, and only load those mySearcher.PropertiesToLoad.Add("name"); mySearcher.PropertiesToLoad.Add("dNSHostName"); mySearcher.PropertiesToLoad.Add("lastLogonTimeStamp"); foreach (SearchResult resEnt in mySearcher.FindAll()) { // Note: Properties can contain multiple values. if (resEnt.Properties["dNSHostName"].Count > 0) { string computerName = (string)resEnt.Properties["dNSHostName"][0]; domainComputers.Add(computerName); } } } this._domainComputers = domainComputers; if (MyOptions.DomainUserRules) { // now users using (DirectorySearcher mySearcher = new DirectorySearcher(entry)) { mySearcher.Filter = ("(objectClass=user)"); // No size limit, reads all objects mySearcher.SizeLimit = 0; // Read data in pages of 250 objects. Make sure this value is below the limit configured in your AD domain (if there is a limit) mySearcher.PageSize = 250; // Let searcher know which properties are going to be used, and only load those mySearcher.PropertiesToLoad.Add("name"); mySearcher.PropertiesToLoad.Add("adminCount"); mySearcher.PropertiesToLoad.Add("sAMAccountName"); mySearcher.PropertiesToLoad.Add("userAccountControl"); foreach (SearchResult resEnt in mySearcher.FindAll()) { try { //busted account name if (resEnt.Properties["sAMAccountName"].Count == 0) { continue; } int uacFlags; bool succes = int.TryParse(resEnt.Properties["userAccountControl"][0].ToString(), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } string userName = (string)resEnt.Properties["sAMAccountName"][0]; // skip computer accounts if (userName.EndsWith("$")) { continue; } if (userName.IndexOf("mailbox", StringComparison.OrdinalIgnoreCase) >= 0) { continue; } if (userName.IndexOf("mbx", StringComparison.OrdinalIgnoreCase) >= 0) { continue; } // if it's got adminCount, keep it if (resEnt.Properties["adminCount"].Count != 0) { if (resEnt.Properties["adminCount"][0].ToString() == "1") { Mq.Trace("Adding " + userName + " to target list because it had adminCount=1."); domainUsers.Add(userName); continue; } } // if the password doesn't expire it's probably a service account if (userAccFlags.HasFlag(UserAccountControlFlags.PasswordDoesNotExpire)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags.DontRequirePreauth)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags.TrustedForDelegation)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags .TrustedToAuthenticateForDelegation)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } // if it matches a string we like, keep it foreach (string str in MyOptions.DomainUserMatchStrings) { if (userName.ToLower().Contains(str.ToLower())) { Mq.Trace("Adding " + userName + " to target list because it contained " + str + "."); domainUsers.Add(userName); break; } } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } } } this._domainUsers = domainUsers; } break; } catch (Exception e) { Mq.Trace(e.ToString()); throw; } } }
public void SetDomainComputers(string LdapFilter) { DirectorySearch ds = GetDirectorySearcher(); List <string> domainComputers = new List <string>(); try { if (!MyOptions.DfsOnly) { // if we aren't limiting the scan to DFS shares then let's get some computer targets. List <string> ldapPropertiesList = new List <string> { "name", "dNSHostName", "lastLogonTimeStamp" }; string ldapFilter = LdapFilter; // extremely dirty hack to break a sig I once saw for Snaffler's LDAP queries. ;-) int num = random.Next(1, 5); while (num > 0) { Guid guid = Guid.NewGuid(); ldapPropertiesList.Add(guid.ToString()); --num; } string[] ldapProperties = ldapPropertiesList.ToArray(); IEnumerable <SearchResultEntry> searchResultEntries = ds.QueryLdap(ldapFilter, ldapProperties, System.DirectoryServices.Protocols.SearchScope.Subtree); // set a window of "the last 4 months" - if a computer hasn't logged in to the domain in 4 months it's probably gone. DateTime validLltsWindow = DateTime.Now.AddMonths(-4); foreach (SearchResultEntry resEnt in searchResultEntries) { int uacFlags; bool success = int.TryParse(resEnt.GetProperty("userAccountControl"), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } try { // get the last logon timestamp value as a datetime string lltsString = resEnt.GetProperty("lastlogontimestamp"); long lltsLong; long.TryParse(lltsString, out lltsLong); DateTime lltsDateTime = DateTime.FromFileTime(lltsLong); // compare it to our window, and if lltsDateTime is older, skip the computer acct. if (lltsDateTime <= validLltsWindow) { continue; } } catch (Exception e) { Mq.Error("Error calculating lastLogonTimeStamp for computer account " + resEnt.DistinguishedName); } if (!String.IsNullOrEmpty(resEnt.GetProperty("dNSHostName"))) { string computerName = resEnt.GetProperty("dNSHostName"); domainComputers.Add(computerName); } } } } catch (Exception e) { Mq.Trace(e.ToString()); } this._domainComputers = domainComputers; }