From 85dc474ef6e213e7baeb3dce1c5aac56c6775bab Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Wed, 16 Oct 2024 16:40:33 -0400 Subject: [PATCH 1/5] wip: fix bad data types in sh --- src/CommonLib/OutputTypes/DomainTrust.cs | 2 +- .../Processors/DomainTrustProcessor.cs | 2 +- .../Processors/LdapPropertyProcessor.cs | 371 ++++++++++++------ 3 files changed, 261 insertions(+), 114 deletions(-) diff --git a/src/CommonLib/OutputTypes/DomainTrust.cs b/src/CommonLib/OutputTypes/DomainTrust.cs index 9c62a82c..446df81d 100644 --- a/src/CommonLib/OutputTypes/DomainTrust.cs +++ b/src/CommonLib/OutputTypes/DomainTrust.cs @@ -9,7 +9,7 @@ public class DomainTrust public bool IsTransitive { get; set; } public bool SidFilteringEnabled { get; set; } public bool TGTDelegationEnabled { get; set; } - public string TrustAttributes { get; set; } + public long TrustAttributes { get; set; } public TrustDirection TrustDirection { get; set; } public TrustType TrustType { get; set; } } diff --git a/src/CommonLib/Processors/DomainTrustProcessor.cs b/src/CommonLib/Processors/DomainTrustProcessor.cs index 16681f9d..42ab5862 100644 --- a/src/CommonLib/Processors/DomainTrustProcessor.cs +++ b/src/CommonLib/Processors/DomainTrustProcessor.cs @@ -71,7 +71,7 @@ public async IAsyncEnumerable EnumerateDomainTrusts(string domain) continue; } - trust.TrustAttributes = ta.ToString(); + trust.TrustAttributes = ta; attributes = (TrustAttributes) ta; trust.IsTransitive = !attributes.HasFlag(TrustAttributes.NonTransitive); diff --git a/src/CommonLib/Processors/LdapPropertyProcessor.cs b/src/CommonLib/Processors/LdapPropertyProcessor.cs index 8577f0fe..d154def9 100644 --- a/src/CommonLib/Processors/LdapPropertyProcessor.cs +++ b/src/CommonLib/Processors/LdapPropertyProcessor.cs @@ -14,11 +14,14 @@ // ReSharper disable StringLiteralTypo -namespace SharpHoundCommonLib.Processors { - public class LdapPropertyProcessor { +namespace SharpHoundCommonLib.Processors +{ + public class LdapPropertyProcessor + { private static readonly HashSet ReservedAttributes = new(); - static LdapPropertyProcessor() { + static LdapPropertyProcessor() + { ReservedAttributes.UnionWith(CommonProperties.TypeResolutionProps); ReservedAttributes.UnionWith(CommonProperties.BaseQueryProps); ReservedAttributes.UnionWith(CommonProperties.GroupResolutionProps); @@ -35,17 +38,21 @@ static LdapPropertyProcessor() { private readonly ILdapUtils _utils; - public LdapPropertyProcessor(ILdapUtils utils) { + public LdapPropertyProcessor(ILdapUtils utils) + { _utils = utils; } - private static Dictionary GetCommonProps(IDirectoryObject entry) { + private static Dictionary GetCommonProps(IDirectoryObject entry) + { var ret = new Dictionary(); - if (entry.TryGetProperty(LDAPProperties.Description, out var description)) { + if (entry.TryGetProperty(LDAPProperties.Description, out var description)) + { ret["description"] = description; } - if (entry.TryGetProperty(LDAPProperties.WhenCreated, out var wc)) { + if (entry.TryGetProperty(LDAPProperties.WhenCreated, out var wc)) + { ret["whencreated"] = Helpers.ConvertTimestampToUnixEpoch(wc); } @@ -60,42 +67,78 @@ private static Dictionary GetCommonProps(IDirectoryObject entry) public async Task> ReadDomainProperties(IDirectoryObject entry, string domain) { var props = GetCommonProps(entry); + + if (entry.TryGetProperty(LDAPProperties.ExpirePasswordsOnSmartCardOnlyAccounts, out var expirePassword) && bool.TryParse(expirePassword, out var expirePasswordBool)) + { + props.Add("expirepasswordsonsmartcardonlyaccounts", expirePasswordBool); + } + + if (entry.TryGetLongProperty(LDAPProperties.MachineAccountQuota, out var machineAccountQuota)) + { + props.Add("machineaccountquota", machineAccountQuota); + } + + if (entry.TryGetLongProperty(LDAPProperties.MinPwdLength, out var minPwdLength)) + { + props.Add("minpwdlength", minPwdLength); + } + if (entry.TryGetLongProperty(LDAPProperties.PwdProperties, out var pwdProperties)) + { + props.Add("pwdproperties", pwdProperties); + } - props.Add("expirepasswordsonsmartcardonlyaccounts", entry.GetProperty(LDAPProperties.ExpirePasswordsOnSmartCardOnlyAccounts)); - props.Add("machineaccountquota", entry.GetProperty(LDAPProperties.MachineAccountQuota)); - props.Add("minpwdlength", entry.GetProperty(LDAPProperties.MinPwdLength)); - props.Add("pwdproperties", entry.GetProperty(LDAPProperties.PwdProperties)); - props.Add("pwdhistorylength", entry.GetProperty(LDAPProperties.PwdHistoryLength)); - props.Add("lockoutthreshold", entry.GetProperty(LDAPProperties.LockoutThreshold)); + if (entry.TryGetLongProperty(LDAPProperties.PwdHistoryLength, out var pwdHistoryLength)) + { + props.Add("pwdhistorylength", pwdHistoryLength); + } - if (entry.TryGetLongProperty(LDAPProperties.MinPwdAge, out var minpwdage)) { + if (entry.TryGetLongProperty(LDAPProperties.LockoutThreshold, out var lockoutThreshold)) + { + props.Add("lockoutthreshold", lockoutThreshold); + } + + if (entry.TryGetLongProperty(LDAPProperties.MinPwdAge, out var minpwdage)) + { var duration = ConvertNanoDuration(minpwdage); - if (duration != null) { + if (duration != null) + { props.Add("minpwdage", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.MaxPwdAge, out var maxpwdage)) { + + if (entry.TryGetLongProperty(LDAPProperties.MaxPwdAge, out var maxpwdage)) + { var duration = ConvertNanoDuration(maxpwdage); - if (duration != null) { + if (duration != null) + { props.Add("maxpwdage", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.LockoutDuration, out var lockoutduration)) { + + if (entry.TryGetLongProperty(LDAPProperties.LockoutDuration, out var lockoutduration)) + { var duration = ConvertNanoDuration(lockoutduration); - if (duration != null) { + if (duration != null) + { props.Add("lockoutduration", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.LockOutObservationWindow, out var lockoutobservationwindow)) { + + if (entry.TryGetLongProperty(LDAPProperties.LockOutObservationWindow, out var lockoutobservationwindow)) + { var duration = ConvertNanoDuration(lockoutobservationwindow); - if (duration != null) { + if (duration != null) + { props.Add("lockoutobservationwindow", lockoutobservationwindow); } } - if (!entry.TryGetLongProperty(LDAPProperties.DomainFunctionalLevel, out var functionalLevel)) { + + if (!entry.TryGetLongProperty(LDAPProperties.DomainFunctionalLevel, out var functionalLevel)) + { functionalLevel = -1; } + props.Add("functionallevel", FunctionalLevelToString((int)functionalLevel)); var dn = entry.GetProperty(LDAPProperties.DistinguishedName); @@ -110,8 +153,10 @@ public async Task> ReadDomainProperties(IDirectoryObj /// /// /// - public static string FunctionalLevelToString(int level) { - var functionalLevel = level switch { + public static string FunctionalLevelToString(int level) + { + var functionalLevel = level switch + { 0 => "2000 Mixed/Native", 1 => "2003 Interim", 2 => "2003", @@ -132,7 +177,8 @@ public static string FunctionalLevelToString(int level) { /// /// /// - public static Dictionary ReadGPOProperties(IDirectoryObject entry) { + public static Dictionary ReadGPOProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); entry.TryGetProperty(LDAPProperties.GPCFileSYSPath, out var path); props.Add("gpcpath", path.ToUpper()); @@ -144,7 +190,8 @@ public static Dictionary ReadGPOProperties(IDirectoryObject entr /// /// /// - public static Dictionary ReadOUProperties(IDirectoryObject entry) { + public static Dictionary ReadOUProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); return props; } @@ -154,7 +201,8 @@ public static Dictionary ReadOUProperties(IDirectoryObject entry /// /// /// - public static Dictionary ReadGroupProperties(IDirectoryObject entry) { + public static Dictionary ReadGroupProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); entry.TryGetLongProperty(LDAPProperties.AdminCount, out var ac); props.Add("admincount", ac != 0); @@ -166,13 +214,15 @@ public static Dictionary ReadGroupProperties(IDirectoryObject en /// /// /// - public static Dictionary ReadContainerProperties(IDirectoryObject entry) { + public static Dictionary ReadContainerProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); return props; } public Task - ReadUserProperties(IDirectoryObject entry, ResolvedSearchResult searchResult) { + ReadUserProperties(IDirectoryObject entry, ResolvedSearchResult searchResult) + { return ReadUserProperties(entry, searchResult.Domain); } @@ -182,12 +232,14 @@ public Task /// /// /// - public async Task ReadUserProperties(IDirectoryObject entry, string domain) { + public async Task ReadUserProperties(IDirectoryObject entry, string domain) + { var userProps = new UserProperties(); var props = GetCommonProps(entry); var uacFlags = (UacFlags)0; - if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) { + if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) + { uacFlags = (UacFlags)uac; } @@ -208,16 +260,19 @@ public async Task ReadUserProperties(IDirectoryObject entry, str var comps = new List(); if (uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation) && - entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) { + entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) + { props.Add("allowedtodelegate", delegates); - foreach (var d in delegates) { + foreach (var d in delegates) + { if (d == null) continue; var resolvedHost = await _utils.ResolveHostToSid(d, domain); if (resolvedHost.Success && resolvedHost.SecurityIdentifier.Contains("S-1")) - comps.Add(new TypedPrincipal { + comps.Add(new TypedPrincipal + { ObjectIdentifier = resolvedHost.SecurityIdentifier, ObjectType = Label.Computer }); @@ -226,19 +281,22 @@ public async Task ReadUserProperties(IDirectoryObject entry, str userProps.AllowedToDelegate = comps.Distinct().ToArray(); - if (!entry.TryGetProperty(LDAPProperties.LastLogon, out var lastLogon)) { + if (!entry.TryGetProperty(LDAPProperties.LastLogon, out var lastLogon)) + { lastLogon = null; } props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(lastLogon)); - if (!entry.TryGetProperty(LDAPProperties.LastLogonTimestamp, out var lastLogonTimeStamp)) { + if (!entry.TryGetProperty(LDAPProperties.LastLogonTimestamp, out var lastLogonTimeStamp)) + { lastLogonTimeStamp = null; } props.Add("lastlogontimestamp", Helpers.ConvertFileTimeToUnixEpoch(lastLogonTimeStamp)); - if (!entry.TryGetProperty(LDAPProperties.PasswordLastSet, out var passwordLastSet)) { + if (!entry.TryGetProperty(LDAPProperties.PasswordLastSet, out var passwordLastSet)) + { passwordLastSet = null; } @@ -268,11 +326,15 @@ public async Task ReadUserProperties(IDirectoryObject entry, str entry.TryGetByteArrayProperty(LDAPProperties.SIDHistory, out var sh); var sidHistoryList = new List(); var sidHistoryPrincipals = new List(); - foreach (var sid in sh) { + foreach (var sid in sh) + { string sSid; - try { + try + { sSid = new SecurityIdentifier(sid, 0).Value; - } catch { + } + catch + { continue; } @@ -292,7 +354,8 @@ public async Task ReadUserProperties(IDirectoryObject entry, str } public Task ReadComputerProperties(IDirectoryObject entry, - ResolvedSearchResult searchResult) { + ResolvedSearchResult searchResult) + { return ReadComputerProperties(entry, searchResult.Domain); } @@ -302,12 +365,14 @@ public Task ReadComputerProperties(IDirectoryObject entry, /// /// /// - public async Task ReadComputerProperties(IDirectoryObject entry, string domain) { + public async Task ReadComputerProperties(IDirectoryObject entry, string domain) + { var compProps = new ComputerProperties(); var props = GetCommonProps(entry); var flags = (UacFlags)0; - if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) { + if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) + { flags = (UacFlags)uac; } @@ -326,16 +391,19 @@ public async Task ReadComputerProperties(IDirectoryObject en var comps = new List(); if (flags.HasFlag(UacFlags.TrustedToAuthForDelegation) && - entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) { + entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) + { props.Add("allowedtodelegate", delegates); - foreach (var d in delegates) { + foreach (var d in delegates) + { if (d == null) continue; var resolvedHost = await _utils.ResolveHostToSid(d, domain); if (resolvedHost.Success && resolvedHost.SecurityIdentifier.Contains("S-1")) - comps.Add(new TypedPrincipal { + comps.Add(new TypedPrincipal + { ObjectIdentifier = resolvedHost.SecurityIdentifier, ObjectType = Label.Computer }); @@ -345,10 +413,12 @@ public async Task ReadComputerProperties(IDirectoryObject en compProps.AllowedToDelegate = comps.Distinct().ToArray(); var allowedToActPrincipals = new List(); - if (entry.TryGetByteProperty(LDAPProperties.AllowedToActOnBehalfOfOtherIdentity, out var rawAllowedToAct)) { + if (entry.TryGetByteProperty(LDAPProperties.AllowedToActOnBehalfOfOtherIdentity, out var rawAllowedToAct)) + { var sd = _utils.MakeSecurityDescriptor(); sd.SetSecurityDescriptorBinaryForm(rawAllowedToAct, AccessControlSections.Access); - foreach (var rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier))) { + foreach (var rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier))) + { if (await _utils.ResolveIDAndType(rule.IdentityReference(), domain) is (true, var res)) allowedToActPrincipals.Add(res); } @@ -375,11 +445,15 @@ public async Task ReadComputerProperties(IDirectoryObject en entry.TryGetByteArrayProperty(LDAPProperties.SIDHistory, out var sh); var sidHistoryList = new List(); var sidHistoryPrincipals = new List(); - foreach (var sid in sh) { + foreach (var sid in sh) + { string sSid; - try { + try + { sSid = new SecurityIdentifier(sid, 0).Value; - } catch { + } + catch + { continue; } @@ -394,8 +468,10 @@ public async Task ReadComputerProperties(IDirectoryObject en props.Add("sidhistory", sidHistoryList.ToArray()); var smsaPrincipals = new List(); - if (entry.TryGetArrayProperty(LDAPProperties.HostServiceAccount, out var hsa)) { - foreach (var dn in hsa) { + if (entry.TryGetArrayProperty(LDAPProperties.HostServiceAccount, out var hsa)) + { + foreach (var dn in hsa) + { if (await _utils.ResolveDistinguishedName(dn) is (true, var resolvedPrincipal)) smsaPrincipals.Add(resolvedPrincipal); } @@ -413,11 +489,13 @@ public async Task ReadComputerProperties(IDirectoryObject en /// /// /// Returns a dictionary with the common properties of the RootCA - public static Dictionary ReadRootCAProperties(IDirectoryObject entry) { + public static Dictionary ReadRootCAProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) + { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -434,7 +512,8 @@ public static Dictionary ReadRootCAProperties(IDirectoryObject e /// /// /// Returns a dictionary with the common properties and the crosscertificatepair property of the AICA - public static Dictionary ReadAIACAProperties(IDirectoryObject entry) { + public static Dictionary ReadAIACAProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); entry.TryGetByteArrayProperty(LDAPProperties.CrossCertificatePair, out var crossCertificatePair); var hasCrossCertificatePair = crossCertificatePair.Length > 0; @@ -443,7 +522,8 @@ public static Dictionary ReadAIACAProperties(IDirectoryObject en props.Add("hascrosscertificatepair", hasCrossCertificatePair); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) + { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -455,7 +535,8 @@ public static Dictionary ReadAIACAProperties(IDirectoryObject en return props; } - public static Dictionary ReadEnterpriseCAProperties(IDirectoryObject entry) { + public static Dictionary ReadEnterpriseCAProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); if (entry.TryGetLongProperty("flags", out var flags)) props.Add("flags", (PKICertificateAuthorityFlags)flags); @@ -463,7 +544,8 @@ public static Dictionary ReadEnterpriseCAProperties(IDirectoryOb props.Add("dnshostname", entry.GetProperty(LDAPProperties.DNSHostName)); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) + { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -480,7 +562,8 @@ public static Dictionary ReadEnterpriseCAProperties(IDirectoryOb /// /// /// Returns a dictionary with the common properties of the NTAuthStore - public static Dictionary ReadNTAuthStoreProperties(IDirectoryObject entry) { + public static Dictionary ReadNTAuthStoreProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); return props; } @@ -490,7 +573,8 @@ public static Dictionary ReadNTAuthStoreProperties(IDirectoryObj /// /// /// Returns a dictionary associated with the CertTemplate properties that were read - public static Dictionary ReadCertTemplateProperties(IDirectoryObject entry) { + public static Dictionary ReadCertTemplateProperties(IDirectoryObject entry) + { var props = GetCommonProps(entry); props.Add("validityperiod", ConvertPKIPeriod(entry.GetByteProperty(LDAPProperties.PKIExpirationPeriod))); @@ -502,7 +586,8 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("displayname", entry.GetProperty(LDAPProperties.DisplayName)); props.Add("oid", entry.GetProperty(LDAPProperties.CertTemplateOID)); - if (entry.TryGetLongProperty(LDAPProperties.PKIEnrollmentFlag, out var enrollmentFlagsRaw)) { + if (entry.TryGetLongProperty(LDAPProperties.PKIEnrollmentFlag, out var enrollmentFlagsRaw)) + { var enrollmentFlags = (PKIEnrollmentFlag)enrollmentFlagsRaw; props.Add("enrollmentflag", enrollmentFlags); @@ -510,7 +595,8 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("nosecurityextension", enrollmentFlags.HasFlag(PKIEnrollmentFlag.NO_SECURITY_EXTENSION)); } - if (entry.TryGetLongProperty(LDAPProperties.PKINameFlag, out var nameFlagsRaw)) { + if (entry.TryGetLongProperty(LDAPProperties.PKINameFlag, out var nameFlagsRaw)) + { var nameFlags = (PKICertificateNameFlag)nameFlagsRaw; props.Add("certificatenameflag", nameFlags); @@ -543,7 +629,8 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("authorizedsignatures", authorizedSignatures); var hasUseLegacyProvider = false; - if (entry.TryGetLongProperty(LDAPProperties.PKIPrivateKeyFlag, out var privateKeyFlagsRaw)) { + if (entry.TryGetLongProperty(LDAPProperties.PKIPrivateKeyFlag, out var privateKeyFlagsRaw)) + { var privateKeyFlags = (PKIPrivateKeyFlag)privateKeyFlagsRaw; hasUseLegacyProvider = privateKeyFlags.HasFlag(PKIPrivateKeyFlag.USE_LEGACY_PROVIDER); } @@ -573,14 +660,17 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb return props; } - public async Task ReadIssuancePolicyProperties(IDirectoryObject entry) { + public async Task ReadIssuancePolicyProperties(IDirectoryObject entry) + { var ret = new IssuancePolicyProperties(); var props = GetCommonProps(entry); props.Add("displayname", entry.GetProperty(LDAPProperties.DisplayName)); props.Add("certtemplateoid", entry.GetProperty(LDAPProperties.CertTemplateOID)); - if (entry.TryGetProperty(LDAPProperties.OIDGroupLink, out var link)) { - if (await _utils.ResolveDistinguishedName(link) is (true, var linkedGroup)) { + if (entry.TryGetProperty(LDAPProperties.OIDGroupLink, out var link)) + { + if (await _utils.ResolveDistinguishedName(link) is (true, var linkedGroup)) + { props.Add("oidgrouplink", linkedGroup.ObjectIdentifier); ret.GroupLink = linkedGroup; } @@ -595,10 +685,12 @@ public async Task ReadIssuancePolicyProperties(IDirect /// format using a best guess /// /// - public Dictionary ParseAllProperties(IDirectoryObject entry) { + public Dictionary ParseAllProperties(IDirectoryObject entry) + { var props = new Dictionary(); - foreach (var property in entry.PropertyNames()) { + foreach (var property in entry.PropertyNames()) + { if (ReservedAttributes.Contains(property, StringComparer.OrdinalIgnoreCase)) continue; @@ -606,40 +698,53 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) { if (collCount == 0) continue; - if (collCount == 1) { + if (collCount == 1) + { var testString = entry.GetProperty(property); - if (!string.IsNullOrEmpty(testString)) { + if (!string.IsNullOrEmpty(testString)) + { if (property.Equals("badpasswordtime", StringComparison.OrdinalIgnoreCase)) props.Add(property, Helpers.ConvertFileTimeToUnixEpoch(testString)); else props.Add(property, BestGuessConvert(testString)); } - } else { - if (entry.TryGetByteProperty(property, out var testBytes)) { - if (testBytes == null || testBytes.Length == 0) { + } + else + { + if (entry.TryGetByteProperty(property, out var testBytes)) + { + if (testBytes == null || testBytes.Length == 0) + { continue; } - + // SIDs - try { + try + { var sid = new SecurityIdentifier(testBytes, 0); props.Add(property, sid.Value); continue; - } catch { + } + catch + { /* Ignore */ } // GUIDs - try { + try + { var guid = new Guid(testBytes); props.Add(property, guid.ToString()); continue; - } catch { + } + catch + { /* Ignore */ } } - if (entry.TryGetArrayProperty(property, out var arr) && arr.Length > 0) { + if (entry.TryGetArrayProperty(property, out var arr) && arr.Length > 0) + { props.Add(property, arr.Select(BestGuessConvert).ToArray()); } } @@ -655,14 +760,18 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) { /// /// private static string[] ParseCertTemplateApplicationPolicies(string[] applicationPolicies, int schemaVersion, - bool hasUseLegacyProvider) { + bool hasUseLegacyProvider) + { if (applicationPolicies == null || applicationPolicies.Length == 0 || schemaVersion == 1 || schemaVersion == 2 - || (schemaVersion == 4 && hasUseLegacyProvider)) { + || (schemaVersion == 4 && hasUseLegacyProvider)) + { return applicationPolicies; - } else { + } + else + { // Format: "Name`Type`Value`Name`Type`Value`..." // (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/c55ec697-be3f-4117-8316-8895e4399237) // Return the Value of Name = "msPKI-RA-Application-Policies" entries @@ -681,7 +790,8 @@ private static string[] ParseCertTemplateApplicationPolicies(string[] applicatio /// /// /// - private static object BestGuessConvert(string value) { + private static object BestGuessConvert(string value) + { //Parse boolean values if (bool.TryParse(value, out var boolResult)) return boolResult; @@ -695,7 +805,8 @@ private static object BestGuessConvert(string value) { if (int.TryParse(value, out var num)) return num; // If we have binary unicode, encode it - foreach (char c in value) { + foreach (char c in value) + { if (char.IsControl(c)) return System.Text.Encoding.UTF8.GetBytes(value); } @@ -705,13 +816,15 @@ private static object BestGuessConvert(string value) { private static List ConvertEncryptionTypes(string encryptionTypes) { - if (encryptionTypes == null) { + if (encryptionTypes == null) + { return null; } int encryptionTypesInt = Int32.Parse(encryptionTypes); List supportedEncryptionTypes = new List(); - if (encryptionTypesInt == 0) { + if (encryptionTypesInt == 0) + { supportedEncryptionTypes.Add("Not defined"); } @@ -719,19 +832,25 @@ private static List ConvertEncryptionTypes(string encryptionTypes) { supportedEncryptionTypes.Add("DES-CBC-CRC"); } + if ((encryptionTypesInt & KerberosEncryptionTypes.DES_CBC_MD5) == KerberosEncryptionTypes.DES_CBC_MD5) { supportedEncryptionTypes.Add("DES-CBC-MD5"); } + if ((encryptionTypesInt & KerberosEncryptionTypes.RC4_HMAC_MD5) == KerberosEncryptionTypes.RC4_HMAC_MD5) { supportedEncryptionTypes.Add("RC4-HMAC-MD5"); } - if ((encryptionTypesInt & KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) == KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) + + if ((encryptionTypesInt & KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) == + KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) { supportedEncryptionTypes.Add("AES128-CTS-HMAC-SHA1-96"); } - if ((encryptionTypesInt & KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) == KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) + + if ((encryptionTypesInt & KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) == + KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) { supportedEncryptionTypes.Add("AES256-CTS-HMAC-SHA1-96"); } @@ -742,10 +861,13 @@ private static List ConvertEncryptionTypes(string encryptionTypes) private static string ConvertNanoDuration(long duration) { // In case duration is long.MinValue, Math.Abs will overflow. Value represents Forever or Never - if (duration == long.MinValue) { + if (duration == long.MinValue) + { return "Forever"; - // And if the value is positive, it indicates an error code - } else if (duration > 0) { + // And if the value is positive, it indicates an error code + } + else if (duration > 0) + { return null; } @@ -761,14 +883,17 @@ private static string ConvertNanoDuration(long duration) { timeComponents.Add($"{durationSpan.Days} {(durationSpan.Days == 1 ? "day" : "days")}"); } + if (durationSpan.Hours > 0) { timeComponents.Add($"{durationSpan.Hours} {(durationSpan.Hours == 1 ? "hour" : "hours")}"); } + if (durationSpan.Minutes > 0) { timeComponents.Add($"{durationSpan.Minutes} {(durationSpan.Minutes == 1 ? "minute" : "minutes")}"); } + if (durationSpan.Seconds > 0) { timeComponents.Add($"{durationSpan.Seconds} {(durationSpan.Seconds == 1 ? "second" : "seconds")}"); @@ -786,47 +911,56 @@ private static string ConvertNanoDuration(long duration) /// https://www.sysadmins.lv/blog-en/how-to-convert-pkiexirationperiod-and-pkioverlapperiod-active-directory-attributes.aspx /// /// Returns a string representing the time period associated with the input byte array in a human readable form - private static string ConvertPKIPeriod(byte[] bytes) { + private static string ConvertPKIPeriod(byte[] bytes) + { if (bytes == null || bytes.Length == 0) return "Unknown"; - try { + try + { Array.Reverse(bytes); var temp = BitConverter.ToString(bytes).Replace("-", ""); var value = Convert.ToInt64(temp, 16) * -.0000001; - if (value % 31536000 == 0 && value / 31536000 >= 1) { + if (value % 31536000 == 0 && value / 31536000 >= 1) + { if (value / 31536000 == 1) return "1 year"; return $"{value / 31536000} years"; } - if (value % 2592000 == 0 && value / 2592000 >= 1) { + if (value % 2592000 == 0 && value / 2592000 >= 1) + { if (value / 2592000 == 1) return "1 month"; return $"{value / 2592000} months"; } - if (value % 604800 == 0 && value / 604800 >= 1) { + if (value % 604800 == 0 && value / 604800 >= 1) + { if (value / 604800 == 1) return "1 week"; return $"{value / 604800} weeks"; } - if (value % 86400 == 0 && value / 86400 >= 1) { + if (value % 86400 == 0 && value / 86400 >= 1) + { if (value / 86400 == 1) return "1 day"; return $"{value / 86400} days"; } - if (value % 3600 == 0 && value / 3600 >= 1) { + if (value % 3600 == 0 && value / 3600 >= 1) + { if (value / 3600 == 1) return "1 hour"; return $"{value / 3600} hours"; } return ""; - } catch (Exception) { + } + catch (Exception) + { return "Unknown"; } } @@ -837,7 +971,8 @@ private static string ConvertPKIPeriod(byte[] bytes) { [Flags] [SuppressMessage("ReSharper", "UnusedMember.Local")] [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum IsTextUnicodeFlags { + private enum IsTextUnicodeFlags + { IS_TEXT_UNICODE_ASCII16 = 0x0001, IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010, @@ -862,38 +997,47 @@ private enum IsTextUnicodeFlags { } } - public class ParsedCertificate { + public class ParsedCertificate + { public string Thumbprint { get; set; } public string Name { get; set; } public string[] Chain { get; set; } public bool HasBasicConstraints { get; set; } public int BasicConstraintPathLength { get; set; } - public ParsedCertificate(byte[] rawCertificate) { + public ParsedCertificate(byte[] rawCertificate) + { var parsedCertificate = new X509Certificate2(rawCertificate); Thumbprint = parsedCertificate.Thumbprint; var name = parsedCertificate.FriendlyName; Name = string.IsNullOrEmpty(name) ? Thumbprint : name; // Chain - try { + try + { var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(parsedCertificate); var temp = new List(); foreach (var cert in chain.ChainElements) temp.Add(cert.Certificate.Thumbprint); Chain = temp.ToArray(); - } catch (Exception e) { - Logging.LogProvider.CreateLogger("ParsedCertificate").LogWarning(e, "Failed to read certificate chain for certificate {Name} with Algo {Algorithm}", name, parsedCertificate.SignatureAlgorithm.FriendlyName); + } + catch (Exception e) + { + Logging.LogProvider.CreateLogger("ParsedCertificate").LogWarning(e, + "Failed to read certificate chain for certificate {Name} with Algo {Algorithm}", name, + parsedCertificate.SignatureAlgorithm.FriendlyName); Chain = Array.Empty(); } - + // Extensions var extensions = parsedCertificate.Extensions; - foreach (var extension in extensions) { + foreach (var extension in extensions) + { var certificateExtension = new CertificateExtension(extension); - switch (certificateExtension.Oid.Value) { + switch (certificateExtension.Oid.Value) + { case CAExtensionTypes.BasicConstraints: var ext = (X509BasicConstraintsExtension)extension; HasBasicConstraints = ext.HasPathLengthConstraint; @@ -904,13 +1048,15 @@ public ParsedCertificate(byte[] rawCertificate) { } } - public class UserProperties { + public class UserProperties + { public Dictionary Props { get; set; } = new(); public TypedPrincipal[] AllowedToDelegate { get; set; } = Array.Empty(); public TypedPrincipal[] SidHistory { get; set; } = Array.Empty(); } - public class ComputerProperties { + public class ComputerProperties + { public Dictionary Props { get; set; } = new(); public TypedPrincipal[] AllowedToDelegate { get; set; } = Array.Empty(); public TypedPrincipal[] AllowedToAct { get; set; } = Array.Empty(); @@ -918,7 +1064,8 @@ public class ComputerProperties { public TypedPrincipal[] DumpSMSAPassword { get; set; } = Array.Empty(); } - public class IssuancePolicyProperties { + public class IssuancePolicyProperties + { public Dictionary Props { get; set; } = new(); public TypedPrincipal GroupLink { get; set; } = new TypedPrincipal(); } From 23b650b78825fb89e3c5887ad0d260fd77b9ebf8 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Mon, 21 Oct 2024 10:43:17 -0400 Subject: [PATCH 2/5] chore: revert formatting to k&r --- .../Processors/LdapPropertyProcessor.cs | 357 ++++++------------ 1 file changed, 120 insertions(+), 237 deletions(-) diff --git a/src/CommonLib/Processors/LdapPropertyProcessor.cs b/src/CommonLib/Processors/LdapPropertyProcessor.cs index d154def9..09a91a2d 100644 --- a/src/CommonLib/Processors/LdapPropertyProcessor.cs +++ b/src/CommonLib/Processors/LdapPropertyProcessor.cs @@ -14,14 +14,11 @@ // ReSharper disable StringLiteralTypo -namespace SharpHoundCommonLib.Processors -{ - public class LdapPropertyProcessor - { +namespace SharpHoundCommonLib.Processors { + public class LdapPropertyProcessor { private static readonly HashSet ReservedAttributes = new(); - static LdapPropertyProcessor() - { + static LdapPropertyProcessor() { ReservedAttributes.UnionWith(CommonProperties.TypeResolutionProps); ReservedAttributes.UnionWith(CommonProperties.BaseQueryProps); ReservedAttributes.UnionWith(CommonProperties.GroupResolutionProps); @@ -38,21 +35,17 @@ static LdapPropertyProcessor() private readonly ILdapUtils _utils; - public LdapPropertyProcessor(ILdapUtils utils) - { + public LdapPropertyProcessor(ILdapUtils utils) { _utils = utils; } - private static Dictionary GetCommonProps(IDirectoryObject entry) - { + private static Dictionary GetCommonProps(IDirectoryObject entry) { var ret = new Dictionary(); - if (entry.TryGetProperty(LDAPProperties.Description, out var description)) - { + if (entry.TryGetProperty(LDAPProperties.Description, out var description)) { ret["description"] = description; } - if (entry.TryGetProperty(LDAPProperties.WhenCreated, out var wc)) - { + if (entry.TryGetProperty(LDAPProperties.WhenCreated, out var wc)) { ret["whencreated"] = Helpers.ConvertTimestampToUnixEpoch(wc); } @@ -64,78 +57,63 @@ private static Dictionary GetCommonProps(IDirectoryObject entry) /// /// /// - public async Task> ReadDomainProperties(IDirectoryObject entry, string domain) - { + public async Task> ReadDomainProperties(IDirectoryObject entry, string domain) { var props = GetCommonProps(entry); - - if (entry.TryGetProperty(LDAPProperties.ExpirePasswordsOnSmartCardOnlyAccounts, out var expirePassword) && bool.TryParse(expirePassword, out var expirePasswordBool)) - { + + if (entry.TryGetProperty(LDAPProperties.ExpirePasswordsOnSmartCardOnlyAccounts, out var expirePassword) && + bool.TryParse(expirePassword, out var expirePasswordBool)) { props.Add("expirepasswordsonsmartcardonlyaccounts", expirePasswordBool); } - if (entry.TryGetLongProperty(LDAPProperties.MachineAccountQuota, out var machineAccountQuota)) - { + if (entry.TryGetLongProperty(LDAPProperties.MachineAccountQuota, out var machineAccountQuota)) { props.Add("machineaccountquota", machineAccountQuota); } - if (entry.TryGetLongProperty(LDAPProperties.MinPwdLength, out var minPwdLength)) - { + if (entry.TryGetLongProperty(LDAPProperties.MinPwdLength, out var minPwdLength)) { props.Add("minpwdlength", minPwdLength); } - if (entry.TryGetLongProperty(LDAPProperties.PwdProperties, out var pwdProperties)) - { + if (entry.TryGetLongProperty(LDAPProperties.PwdProperties, out var pwdProperties)) { props.Add("pwdproperties", pwdProperties); } - if (entry.TryGetLongProperty(LDAPProperties.PwdHistoryLength, out var pwdHistoryLength)) - { + if (entry.TryGetLongProperty(LDAPProperties.PwdHistoryLength, out var pwdHistoryLength)) { props.Add("pwdhistorylength", pwdHistoryLength); } - if (entry.TryGetLongProperty(LDAPProperties.LockoutThreshold, out var lockoutThreshold)) - { + if (entry.TryGetLongProperty(LDAPProperties.LockoutThreshold, out var lockoutThreshold)) { props.Add("lockoutthreshold", lockoutThreshold); } - if (entry.TryGetLongProperty(LDAPProperties.MinPwdAge, out var minpwdage)) - { + if (entry.TryGetLongProperty(LDAPProperties.MinPwdAge, out var minpwdage)) { var duration = ConvertNanoDuration(minpwdage); - if (duration != null) - { + if (duration != null) { props.Add("minpwdage", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.MaxPwdAge, out var maxpwdage)) - { + if (entry.TryGetLongProperty(LDAPProperties.MaxPwdAge, out var maxpwdage)) { var duration = ConvertNanoDuration(maxpwdage); - if (duration != null) - { + if (duration != null) { props.Add("maxpwdage", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.LockoutDuration, out var lockoutduration)) - { + if (entry.TryGetLongProperty(LDAPProperties.LockoutDuration, out var lockoutduration)) { var duration = ConvertNanoDuration(lockoutduration); - if (duration != null) - { + if (duration != null) { props.Add("lockoutduration", duration); } } - if (entry.TryGetLongProperty(LDAPProperties.LockOutObservationWindow, out var lockoutobservationwindow)) - { + if (entry.TryGetLongProperty(LDAPProperties.LockOutObservationWindow, out var lockoutobservationwindow)) { var duration = ConvertNanoDuration(lockoutobservationwindow); - if (duration != null) - { + if (duration != null) { props.Add("lockoutobservationwindow", lockoutobservationwindow); } } - if (!entry.TryGetLongProperty(LDAPProperties.DomainFunctionalLevel, out var functionalLevel)) - { + if (!entry.TryGetLongProperty(LDAPProperties.DomainFunctionalLevel, out var functionalLevel)) { functionalLevel = -1; } @@ -153,10 +131,8 @@ public async Task> ReadDomainProperties(IDirectoryObj /// /// /// - public static string FunctionalLevelToString(int level) - { - var functionalLevel = level switch - { + public static string FunctionalLevelToString(int level) { + var functionalLevel = level switch { 0 => "2000 Mixed/Native", 1 => "2003 Interim", 2 => "2003", @@ -177,8 +153,7 @@ public static string FunctionalLevelToString(int level) /// /// /// - public static Dictionary ReadGPOProperties(IDirectoryObject entry) - { + public static Dictionary ReadGPOProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); entry.TryGetProperty(LDAPProperties.GPCFileSYSPath, out var path); props.Add("gpcpath", path.ToUpper()); @@ -190,8 +165,7 @@ public static Dictionary ReadGPOProperties(IDirectoryObject entr /// /// /// - public static Dictionary ReadOUProperties(IDirectoryObject entry) - { + public static Dictionary ReadOUProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); return props; } @@ -201,8 +175,7 @@ public static Dictionary ReadOUProperties(IDirectoryObject entry /// /// /// - public static Dictionary ReadGroupProperties(IDirectoryObject entry) - { + public static Dictionary ReadGroupProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); entry.TryGetLongProperty(LDAPProperties.AdminCount, out var ac); props.Add("admincount", ac != 0); @@ -214,15 +187,13 @@ public static Dictionary ReadGroupProperties(IDirectoryObject en /// /// /// - public static Dictionary ReadContainerProperties(IDirectoryObject entry) - { + public static Dictionary ReadContainerProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); return props; } public Task - ReadUserProperties(IDirectoryObject entry, ResolvedSearchResult searchResult) - { + ReadUserProperties(IDirectoryObject entry, ResolvedSearchResult searchResult) { return ReadUserProperties(entry, searchResult.Domain); } @@ -232,14 +203,12 @@ public Task /// /// /// - public async Task ReadUserProperties(IDirectoryObject entry, string domain) - { + public async Task ReadUserProperties(IDirectoryObject entry, string domain) { var userProps = new UserProperties(); var props = GetCommonProps(entry); var uacFlags = (UacFlags)0; - if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) - { + if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) { uacFlags = (UacFlags)uac; } @@ -260,19 +229,16 @@ public async Task ReadUserProperties(IDirectoryObject entry, str var comps = new List(); if (uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation) && - entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) - { + entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) { props.Add("allowedtodelegate", delegates); - foreach (var d in delegates) - { + foreach (var d in delegates) { if (d == null) continue; var resolvedHost = await _utils.ResolveHostToSid(d, domain); if (resolvedHost.Success && resolvedHost.SecurityIdentifier.Contains("S-1")) - comps.Add(new TypedPrincipal - { + comps.Add(new TypedPrincipal { ObjectIdentifier = resolvedHost.SecurityIdentifier, ObjectType = Label.Computer }); @@ -281,22 +247,19 @@ public async Task ReadUserProperties(IDirectoryObject entry, str userProps.AllowedToDelegate = comps.Distinct().ToArray(); - if (!entry.TryGetProperty(LDAPProperties.LastLogon, out var lastLogon)) - { + if (!entry.TryGetProperty(LDAPProperties.LastLogon, out var lastLogon)) { lastLogon = null; } props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(lastLogon)); - if (!entry.TryGetProperty(LDAPProperties.LastLogonTimestamp, out var lastLogonTimeStamp)) - { + if (!entry.TryGetProperty(LDAPProperties.LastLogonTimestamp, out var lastLogonTimeStamp)) { lastLogonTimeStamp = null; } props.Add("lastlogontimestamp", Helpers.ConvertFileTimeToUnixEpoch(lastLogonTimeStamp)); - if (!entry.TryGetProperty(LDAPProperties.PasswordLastSet, out var passwordLastSet)) - { + if (!entry.TryGetProperty(LDAPProperties.PasswordLastSet, out var passwordLastSet)) { passwordLastSet = null; } @@ -326,15 +289,12 @@ public async Task ReadUserProperties(IDirectoryObject entry, str entry.TryGetByteArrayProperty(LDAPProperties.SIDHistory, out var sh); var sidHistoryList = new List(); var sidHistoryPrincipals = new List(); - foreach (var sid in sh) - { + foreach (var sid in sh) { string sSid; - try - { + try { sSid = new SecurityIdentifier(sid, 0).Value; } - catch - { + catch { continue; } @@ -354,8 +314,7 @@ public async Task ReadUserProperties(IDirectoryObject entry, str } public Task ReadComputerProperties(IDirectoryObject entry, - ResolvedSearchResult searchResult) - { + ResolvedSearchResult searchResult) { return ReadComputerProperties(entry, searchResult.Domain); } @@ -365,14 +324,12 @@ public Task ReadComputerProperties(IDirectoryObject entry, /// /// /// - public async Task ReadComputerProperties(IDirectoryObject entry, string domain) - { + public async Task ReadComputerProperties(IDirectoryObject entry, string domain) { var compProps = new ComputerProperties(); var props = GetCommonProps(entry); var flags = (UacFlags)0; - if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) - { + if (entry.TryGetLongProperty(LDAPProperties.UserAccountControl, out var uac)) { flags = (UacFlags)uac; } @@ -391,19 +348,16 @@ public async Task ReadComputerProperties(IDirectoryObject en var comps = new List(); if (flags.HasFlag(UacFlags.TrustedToAuthForDelegation) && - entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) - { + entry.TryGetArrayProperty(LDAPProperties.AllowedToDelegateTo, out var delegates)) { props.Add("allowedtodelegate", delegates); - foreach (var d in delegates) - { + foreach (var d in delegates) { if (d == null) continue; var resolvedHost = await _utils.ResolveHostToSid(d, domain); if (resolvedHost.Success && resolvedHost.SecurityIdentifier.Contains("S-1")) - comps.Add(new TypedPrincipal - { + comps.Add(new TypedPrincipal { ObjectIdentifier = resolvedHost.SecurityIdentifier, ObjectType = Label.Computer }); @@ -413,12 +367,10 @@ public async Task ReadComputerProperties(IDirectoryObject en compProps.AllowedToDelegate = comps.Distinct().ToArray(); var allowedToActPrincipals = new List(); - if (entry.TryGetByteProperty(LDAPProperties.AllowedToActOnBehalfOfOtherIdentity, out var rawAllowedToAct)) - { + if (entry.TryGetByteProperty(LDAPProperties.AllowedToActOnBehalfOfOtherIdentity, out var rawAllowedToAct)) { var sd = _utils.MakeSecurityDescriptor(); sd.SetSecurityDescriptorBinaryForm(rawAllowedToAct, AccessControlSections.Access); - foreach (var rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier))) - { + foreach (var rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier))) { if (await _utils.ResolveIDAndType(rule.IdentityReference(), domain) is (true, var res)) allowedToActPrincipals.Add(res); } @@ -445,15 +397,12 @@ public async Task ReadComputerProperties(IDirectoryObject en entry.TryGetByteArrayProperty(LDAPProperties.SIDHistory, out var sh); var sidHistoryList = new List(); var sidHistoryPrincipals = new List(); - foreach (var sid in sh) - { + foreach (var sid in sh) { string sSid; - try - { + try { sSid = new SecurityIdentifier(sid, 0).Value; } - catch - { + catch { continue; } @@ -468,10 +417,8 @@ public async Task ReadComputerProperties(IDirectoryObject en props.Add("sidhistory", sidHistoryList.ToArray()); var smsaPrincipals = new List(); - if (entry.TryGetArrayProperty(LDAPProperties.HostServiceAccount, out var hsa)) - { - foreach (var dn in hsa) - { + if (entry.TryGetArrayProperty(LDAPProperties.HostServiceAccount, out var hsa)) { + foreach (var dn in hsa) { if (await _utils.ResolveDistinguishedName(dn) is (true, var resolvedPrincipal)) smsaPrincipals.Add(resolvedPrincipal); } @@ -489,13 +436,11 @@ public async Task ReadComputerProperties(IDirectoryObject en /// /// /// Returns a dictionary with the common properties of the RootCA - public static Dictionary ReadRootCAProperties(IDirectoryObject entry) - { + public static Dictionary ReadRootCAProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) - { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -512,8 +457,7 @@ public static Dictionary ReadRootCAProperties(IDirectoryObject e /// /// /// Returns a dictionary with the common properties and the crosscertificatepair property of the AICA - public static Dictionary ReadAIACAProperties(IDirectoryObject entry) - { + public static Dictionary ReadAIACAProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); entry.TryGetByteArrayProperty(LDAPProperties.CrossCertificatePair, out var crossCertificatePair); var hasCrossCertificatePair = crossCertificatePair.Length > 0; @@ -522,8 +466,7 @@ public static Dictionary ReadAIACAProperties(IDirectoryObject en props.Add("hascrosscertificatepair", hasCrossCertificatePair); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) - { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -535,8 +478,7 @@ public static Dictionary ReadAIACAProperties(IDirectoryObject en return props; } - public static Dictionary ReadEnterpriseCAProperties(IDirectoryObject entry) - { + public static Dictionary ReadEnterpriseCAProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); if (entry.TryGetLongProperty("flags", out var flags)) props.Add("flags", (PKICertificateAuthorityFlags)flags); @@ -544,8 +486,7 @@ public static Dictionary ReadEnterpriseCAProperties(IDirectoryOb props.Add("dnshostname", entry.GetProperty(LDAPProperties.DNSHostName)); // Certificate - if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) - { + if (entry.TryGetByteProperty(LDAPProperties.CACertificate, out var rawCertificate)) { var cert = new ParsedCertificate(rawCertificate); props.Add("certthumbprint", cert.Thumbprint); props.Add("certname", cert.Name); @@ -562,8 +503,7 @@ public static Dictionary ReadEnterpriseCAProperties(IDirectoryOb /// /// /// Returns a dictionary with the common properties of the NTAuthStore - public static Dictionary ReadNTAuthStoreProperties(IDirectoryObject entry) - { + public static Dictionary ReadNTAuthStoreProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); return props; } @@ -573,8 +513,7 @@ public static Dictionary ReadNTAuthStoreProperties(IDirectoryObj /// /// /// Returns a dictionary associated with the CertTemplate properties that were read - public static Dictionary ReadCertTemplateProperties(IDirectoryObject entry) - { + public static Dictionary ReadCertTemplateProperties(IDirectoryObject entry) { var props = GetCommonProps(entry); props.Add("validityperiod", ConvertPKIPeriod(entry.GetByteProperty(LDAPProperties.PKIExpirationPeriod))); @@ -586,8 +525,7 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("displayname", entry.GetProperty(LDAPProperties.DisplayName)); props.Add("oid", entry.GetProperty(LDAPProperties.CertTemplateOID)); - if (entry.TryGetLongProperty(LDAPProperties.PKIEnrollmentFlag, out var enrollmentFlagsRaw)) - { + if (entry.TryGetLongProperty(LDAPProperties.PKIEnrollmentFlag, out var enrollmentFlagsRaw)) { var enrollmentFlags = (PKIEnrollmentFlag)enrollmentFlagsRaw; props.Add("enrollmentflag", enrollmentFlags); @@ -595,8 +533,7 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("nosecurityextension", enrollmentFlags.HasFlag(PKIEnrollmentFlag.NO_SECURITY_EXTENSION)); } - if (entry.TryGetLongProperty(LDAPProperties.PKINameFlag, out var nameFlagsRaw)) - { + if (entry.TryGetLongProperty(LDAPProperties.PKINameFlag, out var nameFlagsRaw)) { var nameFlags = (PKICertificateNameFlag)nameFlagsRaw; props.Add("certificatenameflag", nameFlags); @@ -629,8 +566,7 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb props.Add("authorizedsignatures", authorizedSignatures); var hasUseLegacyProvider = false; - if (entry.TryGetLongProperty(LDAPProperties.PKIPrivateKeyFlag, out var privateKeyFlagsRaw)) - { + if (entry.TryGetLongProperty(LDAPProperties.PKIPrivateKeyFlag, out var privateKeyFlagsRaw)) { var privateKeyFlags = (PKIPrivateKeyFlag)privateKeyFlagsRaw; hasUseLegacyProvider = privateKeyFlags.HasFlag(PKIPrivateKeyFlag.USE_LEGACY_PROVIDER); } @@ -660,17 +596,14 @@ public static Dictionary ReadCertTemplateProperties(IDirectoryOb return props; } - public async Task ReadIssuancePolicyProperties(IDirectoryObject entry) - { + public async Task ReadIssuancePolicyProperties(IDirectoryObject entry) { var ret = new IssuancePolicyProperties(); var props = GetCommonProps(entry); props.Add("displayname", entry.GetProperty(LDAPProperties.DisplayName)); props.Add("certtemplateoid", entry.GetProperty(LDAPProperties.CertTemplateOID)); - if (entry.TryGetProperty(LDAPProperties.OIDGroupLink, out var link)) - { - if (await _utils.ResolveDistinguishedName(link) is (true, var linkedGroup)) - { + if (entry.TryGetProperty(LDAPProperties.OIDGroupLink, out var link)) { + if (await _utils.ResolveDistinguishedName(link) is (true, var linkedGroup)) { props.Add("oidgrouplink", linkedGroup.ObjectIdentifier); ret.GroupLink = linkedGroup; } @@ -685,12 +618,10 @@ public async Task ReadIssuancePolicyProperties(IDirect /// format using a best guess /// /// - public Dictionary ParseAllProperties(IDirectoryObject entry) - { + public Dictionary ParseAllProperties(IDirectoryObject entry) { var props = new Dictionary(); - foreach (var property in entry.PropertyNames()) - { + foreach (var property in entry.PropertyNames()) { if (ReservedAttributes.Contains(property, StringComparer.OrdinalIgnoreCase)) continue; @@ -698,53 +629,43 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) if (collCount == 0) continue; - if (collCount == 1) - { + if (collCount == 1) { var testString = entry.GetProperty(property); - if (!string.IsNullOrEmpty(testString)) - { + if (!string.IsNullOrEmpty(testString)) { if (property.Equals("badpasswordtime", StringComparison.OrdinalIgnoreCase)) props.Add(property, Helpers.ConvertFileTimeToUnixEpoch(testString)); else props.Add(property, BestGuessConvert(testString)); } } - else - { - if (entry.TryGetByteProperty(property, out var testBytes)) - { - if (testBytes == null || testBytes.Length == 0) - { + else { + if (entry.TryGetByteProperty(property, out var testBytes)) { + if (testBytes == null || testBytes.Length == 0) { continue; } // SIDs - try - { + try { var sid = new SecurityIdentifier(testBytes, 0); props.Add(property, sid.Value); continue; } - catch - { + catch { /* Ignore */ } // GUIDs - try - { + try { var guid = new Guid(testBytes); props.Add(property, guid.ToString()); continue; } - catch - { + catch { /* Ignore */ } } - if (entry.TryGetArrayProperty(property, out var arr) && arr.Length > 0) - { + if (entry.TryGetArrayProperty(property, out var arr) && arr.Length > 0) { props.Add(property, arr.Select(BestGuessConvert).ToArray()); } } @@ -760,18 +681,15 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) /// /// private static string[] ParseCertTemplateApplicationPolicies(string[] applicationPolicies, int schemaVersion, - bool hasUseLegacyProvider) - { + bool hasUseLegacyProvider) { if (applicationPolicies == null || applicationPolicies.Length == 0 || schemaVersion == 1 || schemaVersion == 2 - || (schemaVersion == 4 && hasUseLegacyProvider)) - { + || (schemaVersion == 4 && hasUseLegacyProvider)) { return applicationPolicies; } - else - { + else { // Format: "Name`Type`Value`Name`Type`Value`..." // (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/c55ec697-be3f-4117-8316-8895e4399237) // Return the Value of Name = "msPKI-RA-Application-Policies" entries @@ -790,8 +708,7 @@ private static string[] ParseCertTemplateApplicationPolicies(string[] applicatio /// /// /// - private static object BestGuessConvert(string value) - { + private static object BestGuessConvert(string value) { //Parse boolean values if (bool.TryParse(value, out var boolResult)) return boolResult; @@ -805,8 +722,7 @@ private static object BestGuessConvert(string value) if (int.TryParse(value, out var num)) return num; // If we have binary unicode, encode it - foreach (char c in value) - { + foreach (char c in value) { if (char.IsControl(c)) return System.Text.Encoding.UTF8.GetBytes(value); } @@ -814,60 +730,49 @@ private static object BestGuessConvert(string value) return value; } - private static List ConvertEncryptionTypes(string encryptionTypes) - { - if (encryptionTypes == null) - { + private static List ConvertEncryptionTypes(string encryptionTypes) { + if (encryptionTypes == null) { return null; } int encryptionTypesInt = Int32.Parse(encryptionTypes); List supportedEncryptionTypes = new List(); - if (encryptionTypesInt == 0) - { + if (encryptionTypesInt == 0) { supportedEncryptionTypes.Add("Not defined"); } - if ((encryptionTypesInt & KerberosEncryptionTypes.DES_CBC_CRC) == KerberosEncryptionTypes.DES_CBC_CRC) - { + if ((encryptionTypesInt & KerberosEncryptionTypes.DES_CBC_CRC) == KerberosEncryptionTypes.DES_CBC_CRC) { supportedEncryptionTypes.Add("DES-CBC-CRC"); } - if ((encryptionTypesInt & KerberosEncryptionTypes.DES_CBC_MD5) == KerberosEncryptionTypes.DES_CBC_MD5) - { + if ((encryptionTypesInt & KerberosEncryptionTypes.DES_CBC_MD5) == KerberosEncryptionTypes.DES_CBC_MD5) { supportedEncryptionTypes.Add("DES-CBC-MD5"); } - if ((encryptionTypesInt & KerberosEncryptionTypes.RC4_HMAC_MD5) == KerberosEncryptionTypes.RC4_HMAC_MD5) - { + if ((encryptionTypesInt & KerberosEncryptionTypes.RC4_HMAC_MD5) == KerberosEncryptionTypes.RC4_HMAC_MD5) { supportedEncryptionTypes.Add("RC4-HMAC-MD5"); } if ((encryptionTypesInt & KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) == - KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) - { + KerberosEncryptionTypes.AES128_CTS_HMAC_SHA1_96) { supportedEncryptionTypes.Add("AES128-CTS-HMAC-SHA1-96"); } if ((encryptionTypesInt & KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) == - KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) - { + KerberosEncryptionTypes.AES256_CTS_HMAC_SHA1_96) { supportedEncryptionTypes.Add("AES256-CTS-HMAC-SHA1-96"); } return supportedEncryptionTypes; } - private static string ConvertNanoDuration(long duration) - { + private static string ConvertNanoDuration(long duration) { // In case duration is long.MinValue, Math.Abs will overflow. Value represents Forever or Never - if (duration == long.MinValue) - { + if (duration == long.MinValue) { return "Forever"; // And if the value is positive, it indicates an error code } - else if (duration > 0) - { + else if (duration > 0) { return null; } @@ -879,23 +784,19 @@ private static string ConvertNanoDuration(long duration) List timeComponents = new List(); // Add each time component if it's greater than zero - if (durationSpan.Days > 0) - { + if (durationSpan.Days > 0) { timeComponents.Add($"{durationSpan.Days} {(durationSpan.Days == 1 ? "day" : "days")}"); } - if (durationSpan.Hours > 0) - { + if (durationSpan.Hours > 0) { timeComponents.Add($"{durationSpan.Hours} {(durationSpan.Hours == 1 ? "hour" : "hours")}"); } - if (durationSpan.Minutes > 0) - { + if (durationSpan.Minutes > 0) { timeComponents.Add($"{durationSpan.Minutes} {(durationSpan.Minutes == 1 ? "minute" : "minutes")}"); } - if (durationSpan.Seconds > 0) - { + if (durationSpan.Seconds > 0) { timeComponents.Add($"{durationSpan.Seconds} {(durationSpan.Seconds == 1 ? "second" : "seconds")}"); } @@ -911,47 +812,40 @@ private static string ConvertNanoDuration(long duration) /// https://www.sysadmins.lv/blog-en/how-to-convert-pkiexirationperiod-and-pkioverlapperiod-active-directory-attributes.aspx /// /// Returns a string representing the time period associated with the input byte array in a human readable form - private static string ConvertPKIPeriod(byte[] bytes) - { + private static string ConvertPKIPeriod(byte[] bytes) { if (bytes == null || bytes.Length == 0) return "Unknown"; - try - { + try { Array.Reverse(bytes); var temp = BitConverter.ToString(bytes).Replace("-", ""); var value = Convert.ToInt64(temp, 16) * -.0000001; - if (value % 31536000 == 0 && value / 31536000 >= 1) - { + if (value % 31536000 == 0 && value / 31536000 >= 1) { if (value / 31536000 == 1) return "1 year"; return $"{value / 31536000} years"; } - if (value % 2592000 == 0 && value / 2592000 >= 1) - { + if (value % 2592000 == 0 && value / 2592000 >= 1) { if (value / 2592000 == 1) return "1 month"; return $"{value / 2592000} months"; } - if (value % 604800 == 0 && value / 604800 >= 1) - { + if (value % 604800 == 0 && value / 604800 >= 1) { if (value / 604800 == 1) return "1 week"; return $"{value / 604800} weeks"; } - if (value % 86400 == 0 && value / 86400 >= 1) - { + if (value % 86400 == 0 && value / 86400 >= 1) { if (value / 86400 == 1) return "1 day"; return $"{value / 86400} days"; } - if (value % 3600 == 0 && value / 3600 >= 1) - { + if (value % 3600 == 0 && value / 3600 >= 1) { if (value / 3600 == 1) return "1 hour"; return $"{value / 3600} hours"; @@ -959,8 +853,7 @@ private static string ConvertPKIPeriod(byte[] bytes) return ""; } - catch (Exception) - { + catch (Exception) { return "Unknown"; } } @@ -971,8 +864,7 @@ private static string ConvertPKIPeriod(byte[] bytes) [Flags] [SuppressMessage("ReSharper", "UnusedMember.Local")] [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum IsTextUnicodeFlags - { + private enum IsTextUnicodeFlags { IS_TEXT_UNICODE_ASCII16 = 0x0001, IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010, @@ -997,24 +889,21 @@ private enum IsTextUnicodeFlags } } - public class ParsedCertificate - { + public class ParsedCertificate { public string Thumbprint { get; set; } public string Name { get; set; } public string[] Chain { get; set; } public bool HasBasicConstraints { get; set; } public int BasicConstraintPathLength { get; set; } - public ParsedCertificate(byte[] rawCertificate) - { + public ParsedCertificate(byte[] rawCertificate) { var parsedCertificate = new X509Certificate2(rawCertificate); Thumbprint = parsedCertificate.Thumbprint; var name = parsedCertificate.FriendlyName; Name = string.IsNullOrEmpty(name) ? Thumbprint : name; // Chain - try - { + try { var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(parsedCertificate); @@ -1022,8 +911,7 @@ public ParsedCertificate(byte[] rawCertificate) foreach (var cert in chain.ChainElements) temp.Add(cert.Certificate.Thumbprint); Chain = temp.ToArray(); } - catch (Exception e) - { + catch (Exception e) { Logging.LogProvider.CreateLogger("ParsedCertificate").LogWarning(e, "Failed to read certificate chain for certificate {Name} with Algo {Algorithm}", name, parsedCertificate.SignatureAlgorithm.FriendlyName); @@ -1033,11 +921,9 @@ public ParsedCertificate(byte[] rawCertificate) // Extensions var extensions = parsedCertificate.Extensions; - foreach (var extension in extensions) - { + foreach (var extension in extensions) { var certificateExtension = new CertificateExtension(extension); - switch (certificateExtension.Oid.Value) - { + switch (certificateExtension.Oid.Value) { case CAExtensionTypes.BasicConstraints: var ext = (X509BasicConstraintsExtension)extension; HasBasicConstraints = ext.HasPathLengthConstraint; @@ -1048,15 +934,13 @@ public ParsedCertificate(byte[] rawCertificate) } } - public class UserProperties - { + public class UserProperties { public Dictionary Props { get; set; } = new(); public TypedPrincipal[] AllowedToDelegate { get; set; } = Array.Empty(); public TypedPrincipal[] SidHistory { get; set; } = Array.Empty(); } - public class ComputerProperties - { + public class ComputerProperties { public Dictionary Props { get; set; } = new(); public TypedPrincipal[] AllowedToDelegate { get; set; } = Array.Empty(); public TypedPrincipal[] AllowedToAct { get; set; } = Array.Empty(); @@ -1064,8 +948,7 @@ public class ComputerProperties public TypedPrincipal[] DumpSMSAPassword { get; set; } = Array.Empty(); } - public class IssuancePolicyProperties - { + public class IssuancePolicyProperties { public Dictionary Props { get; set; } = new(); public TypedPrincipal GroupLink { get; set; } = new TypedPrincipal(); } From 8993bec3d086170f3ba04902dec5500413b529e7 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Mon, 21 Oct 2024 10:44:32 -0400 Subject: [PATCH 3/5] chore: fix more formatting --- .../Processors/LdapPropertyProcessor.cs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/CommonLib/Processors/LdapPropertyProcessor.cs b/src/CommonLib/Processors/LdapPropertyProcessor.cs index 09a91a2d..3c640650 100644 --- a/src/CommonLib/Processors/LdapPropertyProcessor.cs +++ b/src/CommonLib/Processors/LdapPropertyProcessor.cs @@ -293,8 +293,7 @@ public async Task ReadUserProperties(IDirectoryObject entry, str string sSid; try { sSid = new SecurityIdentifier(sid, 0).Value; - } - catch { + } catch { continue; } @@ -401,8 +400,7 @@ public async Task ReadComputerProperties(IDirectoryObject en string sSid; try { sSid = new SecurityIdentifier(sid, 0).Value; - } - catch { + } catch { continue; } @@ -637,8 +635,7 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) { else props.Add(property, BestGuessConvert(testString)); } - } - else { + } else { if (entry.TryGetByteProperty(property, out var testBytes)) { if (testBytes == null || testBytes.Length == 0) { continue; @@ -649,8 +646,7 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) { var sid = new SecurityIdentifier(testBytes, 0); props.Add(property, sid.Value); continue; - } - catch { + } catch { /* Ignore */ } @@ -659,8 +655,7 @@ public Dictionary ParseAllProperties(IDirectoryObject entry) { var guid = new Guid(testBytes); props.Add(property, guid.ToString()); continue; - } - catch { + } catch { /* Ignore */ } } @@ -688,8 +683,7 @@ private static string[] ParseCertTemplateApplicationPolicies(string[] applicatio || schemaVersion == 2 || (schemaVersion == 4 && hasUseLegacyProvider)) { return applicationPolicies; - } - else { + } else { // Format: "Name`Type`Value`Name`Type`Value`..." // (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/c55ec697-be3f-4117-8316-8895e4399237) // Return the Value of Name = "msPKI-RA-Application-Policies" entries @@ -771,8 +765,7 @@ private static string ConvertNanoDuration(long duration) { if (duration == long.MinValue) { return "Forever"; // And if the value is positive, it indicates an error code - } - else if (duration > 0) { + } else if (duration > 0) { return null; } @@ -852,8 +845,7 @@ private static string ConvertPKIPeriod(byte[] bytes) { } return ""; - } - catch (Exception) { + } catch (Exception) { return "Unknown"; } } @@ -910,8 +902,7 @@ public ParsedCertificate(byte[] rawCertificate) { var temp = new List(); foreach (var cert in chain.ChainElements) temp.Add(cert.Certificate.Thumbprint); Chain = temp.ToArray(); - } - catch (Exception e) { + } catch (Exception e) { Logging.LogProvider.CreateLogger("ParsedCertificate").LogWarning(e, "Failed to read certificate chain for certificate {Name} with Algo {Algorithm}", name, parsedCertificate.SignatureAlgorithm.FriendlyName); From ead8b73e5ce6bc19d07ca53293306edf733c08a5 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Mon, 21 Oct 2024 11:12:15 -0400 Subject: [PATCH 4/5] fix: elevate try/catch on principalcontext calls to fix exceptions https://github.com/BloodHoundAD/SharpHound/issues/120 --- src/CommonLib/LdapUtils.cs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/CommonLib/LdapUtils.cs b/src/CommonLib/LdapUtils.cs index 17293d3b..e29defc7 100644 --- a/src/CommonLib/LdapUtils.cs +++ b/src/CommonLib/LdapUtils.cs @@ -168,8 +168,8 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame //pass } - using (var ctx = new PrincipalContext(ContextType.Domain)) { - try { + try { + using (var ctx = new PrincipalContext(ContextType.Domain)) { var principal = Principal.FindByIdentity(ctx, IdentityType.Sid, sid); if (principal != null) { var entry = ((DirectoryEntry)principal.GetUnderlyingObject()).ToDirectoryObject(); @@ -178,10 +178,11 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame return (true, type); } } - } catch { - //pass } + } catch { + //pass } + return (false, Label.Base); } @@ -212,8 +213,8 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame //pass } - using (var ctx = new PrincipalContext(ContextType.Domain)) { - try { + try { + using (var ctx = new PrincipalContext(ContextType.Domain)) { var principal = Principal.FindByIdentity(ctx, IdentityType.Guid, guid); if (principal != null) { var entry = ((DirectoryEntry)principal.GetUnderlyingObject()).ToDirectoryObject(); @@ -222,10 +223,11 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame return (true, type); } } - } catch { - //pass } + } catch { + //pass } + return (false, Label.Base); } @@ -345,8 +347,8 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame return (true, domainName); } - using (var ctx = new PrincipalContext(ContextType.Domain)) { - try { + try { + using (var ctx = new PrincipalContext(ContextType.Domain)) { var principal = Principal.FindByIdentity(ctx, IdentityType.Sid, sid); if (principal != null) { var dn = principal.DistinguishedName; @@ -355,10 +357,11 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame return (true, Helpers.DistinguishedNameToDomain(dn)); } } - } catch { - //pass } + } catch { + //pass } + return (false, string.Empty); } @@ -877,8 +880,8 @@ public async Task IsDomainController(string computerObjectId, string domai return (true, principal); } - using (var ctx = new PrincipalContext(ContextType.Domain)) { - try { + try { + using (var ctx = new PrincipalContext(ContextType.Domain)) { var lookupPrincipal = Principal.FindByIdentity(ctx, IdentityType.DistinguishedName, distinguishedName); if (lookupPrincipal != null) { @@ -895,12 +898,13 @@ public async Task IsDomainController(string computerObjectId, string domai } } - return (false, default); - } catch { - _unresolvablePrincipals.Add(distinguishedName); return (false, default); } + } catch { + _unresolvablePrincipals.Add(distinguishedName); + return (false, default); } + } public async Task<(bool Success, string DSHeuristics)> GetDSHueristics(string domain, string dn) { From 1e81e8cef468df84b70a41b9bb8dd4166906b55b Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Mon, 21 Oct 2024 12:14:07 -0400 Subject: [PATCH 5/5] chore: add lock on buildguidcache --- src/CommonLib/Processors/ACLProcessor.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/CommonLib/Processors/ACLProcessor.cs b/src/CommonLib/Processors/ACLProcessor.cs index 7afbb9d5..907ad758 100644 --- a/src/CommonLib/Processors/ACLProcessor.cs +++ b/src/CommonLib/Processors/ACLProcessor.cs @@ -19,6 +19,7 @@ public class ACLProcessor { private readonly ILogger _log; private readonly ILdapUtils _utils; private readonly ConcurrentHashSet _builtDomainCaches = new(StringComparer.OrdinalIgnoreCase); + private readonly object _lock = new(); static ACLProcessor() { //Create a dictionary with the base GUIDs of each object type @@ -50,6 +51,14 @@ public ACLProcessor(ILdapUtils utils, ILogger log = null) { /// LAPS /// private async Task BuildGuidCache(string domain) { + lock (_lock) { + if (_builtDomainCaches.Contains(domain)) { + return; + } + + _builtDomainCaches.Add(domain); + } + _log.LogInformation("Building GUID Cache for {Domain}", domain); await foreach (var result in _utils.PagedQuery(new LdapQueryParameters { DomainName = domain, @@ -82,6 +91,7 @@ private async Task BuildGuidCache(string domain) { _log.LogDebug("Error while building GUID cache for {Domain}: {Message}", domain, result.Error); } } + } /// @@ -227,10 +237,7 @@ public IEnumerable GetInheritedAceHashes(byte[] ntSecurityDescriptor, st public async IAsyncEnumerable ProcessACL(byte[] ntSecurityDescriptor, string objectDomain, Label objectType, bool hasLaps, string objectName = "") { - if (!_builtDomainCaches.Contains(objectDomain)) { - _builtDomainCaches.Add(objectDomain); - await BuildGuidCache(objectDomain); - } + await BuildGuidCache(objectDomain); if (ntSecurityDescriptor == null) { _log.LogDebug("Security Descriptor is null for {Name}", objectName);