diff --git a/src/CommonLib/Processors/LDAPPropertyProcessor.cs b/src/CommonLib/Processors/LDAPPropertyProcessor.cs index 1fe66830..87a09b7a 100644 --- a/src/CommonLib/Processors/LDAPPropertyProcessor.cs +++ b/src/CommonLib/Processors/LDAPPropertyProcessor.cs @@ -150,40 +150,23 @@ public async Task ReadUserProperties(ISearchResultEntry entry) var props = GetCommonProps(entry); var uac = entry.GetProperty(LDAPProperties.UserAccountControl); - bool enabled, trustedToAuth, sensitive, dontReqPreAuth, passwdNotReq, unconstrained, pwdNeverExpires; - if (int.TryParse(uac, out var flag)) + var uacFlags = (UacFlags)0; + if (entry.GetIntProperty(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; - pwdNeverExpires = (flags & UacFlags.DontExpirePassword) != 0; - } - else - { - trustedToAuth = false; - enabled = true; - sensitive = false; - dontReqPreAuth = false; - passwdNotReq = false; - unconstrained = false; - pwdNeverExpires = false; + uacFlags = (UacFlags)flag; + props.Add("sensitive", uacFlags.HasFlag(UacFlags.NotDelegated)); + props.Add("dontreqpreauth", uacFlags.HasFlag(UacFlags.DontReqPreauth)); + props.Add("passwordnotreqd", uacFlags.HasFlag(UacFlags.PasswordNotRequired)); + props.Add("unconstraineddelegation", uacFlags.HasFlag(UacFlags.TrustedForDelegation)); + props.Add("pwdneverexpires", uacFlags.HasFlag(UacFlags.DontExpirePassword)); + props.Add("enabled", !uacFlags.HasFlag(UacFlags.AccountDisable)); + props.Add("trustedtoauth", uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation)); } - props.Add("sensitive", sensitive); - props.Add("dontreqpreauth", dontReqPreAuth); - props.Add("passwordnotreqd", passwdNotReq); - props.Add("unconstraineddelegation", unconstrained); - props.Add("pwdneverexpires", pwdNeverExpires); - props.Add("enabled", enabled); - props.Add("trustedtoauth", trustedToAuth); var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName); var comps = new List(); - if (trustedToAuth) + if (uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation)) { var delegates = entry.GetArrayProperty(LDAPProperties.AllowedToDelegateTo); props.Add("allowedtodelegate", delegates); @@ -278,25 +261,20 @@ public async Task ReadComputerProperties(ISearchResultEntry var props = GetCommonProps(entry); var uac = entry.GetProperty(LDAPProperties.UserAccountControl); - bool enabled, unconstrained, trustedToAuth; - if (int.TryParse(uac, out var flag)) + var flags = (UacFlags)0; + if (entry.GetIntProperty(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; + flags = (UacFlags)flag; + props.Add("enabled", !flags.HasFlag(UacFlags.AccountDisable)); + props.Add("unconstraineddelegation", flags.HasFlag(UacFlags.TrustedForDelegation)); + props.Add("trustedtoauth", flags.HasFlag(UacFlags.TrustedToAuthForDelegation)); + props.Add("isdc", flags.HasFlag(UacFlags.ServerTrustAccount)); } var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName); var comps = new List(); - if (trustedToAuth) + if (flags.HasFlag(UacFlags.TrustedToAuthForDelegation)) { var delegates = entry.GetArrayProperty(LDAPProperties.AllowedToDelegateTo); props.Add("allowedtodelegate", delegates); @@ -332,15 +310,13 @@ public async Task ReadComputerProperties(ISearchResultEntry compProps.AllowedToAct = allowedToActPrincipals.ToArray(); - props.Add("enabled", enabled); - props.Add("unconstraineddelegation", unconstrained); - props.Add("trustedtoauth", trustedToAuth); props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogon))); props.Add("lastlogontimestamp", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogonTimestamp))); props.Add("pwdlastset", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.PasswordLastSet))); props.Add("serviceprincipalnames", entry.GetArrayProperty(LDAPProperties.ServicePrincipalNames)); + props.Add("email", entry.GetProperty(LDAPProperties.Email)); var os = entry.GetProperty(LDAPProperties.OperatingSystem); var sp = entry.GetProperty(LDAPProperties.ServicePack); @@ -516,6 +492,16 @@ public static Dictionary ReadCertTemplateProperties(ISearchResul nameFlags.HasFlag(PKICertificateNameFlag.ENROLLEE_SUPPLIES_SUBJECT)); props.Add("subjectaltrequireupn", nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_UPN)); + props.Add("subjectaltrequiredns", + nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_DNS)); + props.Add("subjectaltrequiredomaindns", + nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_DOMAIN_DNS)); + props.Add("subjectaltrequireemail", + nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_EMAIL)); + props.Add("subjectaltrequirespn", + nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_SPN)); + props.Add("subjectrequireemail", + nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_REQUIRE_EMAIL)); } string[] ekus = entry.GetArrayProperty(LDAPProperties.ExtendedKeyUsage); @@ -761,4 +747,4 @@ public class ComputerProperties public TypedPrincipal[] SidHistory { get; set; } = Array.Empty(); public TypedPrincipal[] DumpSMSAPassword { get; set; } = Array.Empty(); } -} \ No newline at end of file +} diff --git a/src/CommonLib/SearchResultEntryWrapper.cs b/src/CommonLib/SearchResultEntryWrapper.cs index 0f0856e3..2e191c02 100644 --- a/src/CommonLib/SearchResultEntryWrapper.cs +++ b/src/CommonLib/SearchResultEntryWrapper.cs @@ -63,7 +63,7 @@ public ResolvedSearchResult ResolveBloodHoundInfo() if (int.TryParse(uac, out var flag)) { var flags = (UacFlags) flag; - if ((flags & UacFlags.ServerTrustAccount) != 0) + if (flags.HasFlag(UacFlags.ServerTrustAccount)) { _log.LogTrace("Marked {SID} as a domain controller", objectId); res.IsDomainController = true; diff --git a/test/unit/LDAPPropertyTests.cs b/test/unit/LDAPPropertyTests.cs index ab71cf83..86a979a9 100644 --- a/test/unit/LDAPPropertyTests.cs +++ b/test/unit/LDAPPropertyTests.cs @@ -264,6 +264,7 @@ public async Task LDAPPropertyProcessor_ReadUserProperties_HappyPath() {"lastlogon", "132673011142753043"}, {"lastlogontimestamp", "132670318095676525"}, {"homedirectory", @"\\win10\testdir"}, + {"email", "test@testdomain.com"}, { "serviceprincipalname", new[] { @@ -298,6 +299,8 @@ public async Task LDAPPropertyProcessor_ReadUserProperties_HappyPath() Assert.Equal(1568693134, (long)props["pwdlastset"]); Assert.Contains("homedirectory", keys); Assert.Equal(@"\\win10\testdir", props["homedirectory"] as string); + Assert.Contains("email", keys); + Assert.Equal("test@testdomain.com", props["email"] as string); //UAC stuff Assert.Contains("sensitive", keys); @@ -397,6 +400,7 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath() {"lastlogontimestamp", "132670318095676525"}, {"operatingsystem", "Windows 10 Enterprise"}, {"operatingsystemservicepack", "1607"}, + {"email", "test@testdomain.com"}, {"admincount", "c"}, { "sidhistory", new[] @@ -434,11 +438,15 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath() //UAC Assert.Contains("enabled", keys); Assert.Contains("unconstraineddelegation", keys); + Assert.Contains("trustedtoauth", keys); + Assert.Contains("isdc", keys); Assert.Contains("lastlogon", keys); Assert.Contains("lastlogontimestamp", keys); Assert.Contains("pwdlastset", keys); Assert.True((bool)props["enabled"]); Assert.False((bool)props["unconstraineddelegation"]); + Assert.False((bool)props["trustedtoauth"]); + Assert.False((bool)props["isdc"]); Assert.Contains("lastlogon", keys); Assert.Equal(1622827514, (long)props["lastlogon"]); @@ -462,6 +470,8 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath() Assert.Equal("Windows 10 Enterprise 1607", props["operatingsystem"] as string); Assert.Contains("description", keys); Assert.Equal("Test", props["description"] as string); + Assert.Contains("email", keys); + Assert.Equal("test@testdomain.com", props["email"] as string); //SidHistory Assert.Contains("sidhistory", keys); @@ -700,9 +710,7 @@ public void LDAPPropertyProcessor_ReadCertTemplateProperties() {"oid", "1.3.6.1.4.1.311.21.8.4571196.1884641.3293620.10686285.12068043.134.1.30"}, {"enrollmentflag", 32}, {"requiresmanagerapproval", false}, - {"certificatenameflag", 134217728}, - {"enrolleesuppliessubject", false}, - {"subjectaltrequireupn", false}, + {"certificatenameflag", 0x8000000}, {"ekus", new[] {"1.3.6.1.5.5.7.3.2"} }, @@ -739,6 +747,11 @@ public void LDAPPropertyProcessor_ReadCertTemplateProperties() Assert.Contains("certificatenameflag", keys); Assert.Contains("enrolleesuppliessubject", keys); Assert.Contains("subjectaltrequireupn", keys); + Assert.Contains("subjectaltrequiredns", keys); + Assert.Contains("subjectaltrequiredomaindns", keys); + Assert.Contains("subjectaltrequireemail", keys); + Assert.Contains("subjectaltrequirespn", keys); + Assert.Contains("subjectrequireemail", keys); Assert.Contains("ekus", keys); Assert.Contains("certificateapplicationpolicy", keys); Assert.Contains("authorizedsignatures", keys); @@ -833,4 +846,4 @@ public void LDAPPropertyProcessor_ParseAllProperties_CollectionCountOne_NotBadPa } } -} \ No newline at end of file +}