From f312535a20bd19044312902d7a09d27da69d32dc Mon Sep 17 00:00:00 2001 From: 0cmenog Date: Tue, 24 Oct 2023 09:05:36 -0700 Subject: [PATCH] add extraction of LDAP Channel Binding and Cached Logons --- .../OutputTypes/ResultingGPOChanges.cs | 1 + .../Processors/GPOLocalGroupProcessor.cs | 69 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/CommonLib/OutputTypes/ResultingGPOChanges.cs b/src/CommonLib/OutputTypes/ResultingGPOChanges.cs index 6909d1f2..8314bac9 100644 --- a/src/CommonLib/OutputTypes/ResultingGPOChanges.cs +++ b/src/CommonLib/OutputTypes/ResultingGPOChanges.cs @@ -22,5 +22,6 @@ public class GPOChanges public Dictionary SMBSigning = new(); public Dictionary LDAPSigning = new(); public Dictionary LMAuthenticationLevel = new(); + public Dictionary MSCache = new(); } } \ No newline at end of file diff --git a/src/CommonLib/Processors/GPOLocalGroupProcessor.cs b/src/CommonLib/Processors/GPOLocalGroupProcessor.cs index 59d1a871..74e4ea55 100644 --- a/src/CommonLib/Processors/GPOLocalGroupProcessor.cs +++ b/src/CommonLib/Processors/GPOLocalGroupProcessor.cs @@ -86,6 +86,12 @@ public class GPOLocalGroupProcessor private static readonly Regex LMLevelRegex = new(@"\\LmCompatibilityLevel *= *\d+ *, *(\d)", RegexOptions.Compiled); + private static readonly Regex CachedLogonsCountRegex = + new(@"\\CachedLogonsCount *= *\d+ *, *\x22(\d+)\x22", RegexOptions.Compiled); + + private static readonly Regex LDAPEnforceChannelBindingRegex = + new(@"\\LdapEnforceChannelBinding *= *\d+ *, *(\d)", RegexOptions.Compiled); + private static readonly ConcurrentDictionary> GpoActionCache = new(); private static readonly Dictionary ValidGroupNames = @@ -227,10 +233,22 @@ public async Task ReadGPOLocalGroups(string gpLink, string } // Add LM properties - _ = enforced.Contains(linkDn) ? (ret.Enforced.LMAuthenticationLevel = item.GPOLMProps) : (ret.Unenforced.LMAuthenticationLevel = item.GPOLMProps); + foreach (var i in item.GPOLMProps) + { + _ = enforced.Contains(linkDn) ? (ret.Enforced.LMAuthenticationLevel = item.GPOLMProps) : (ret.Unenforced.LMAuthenticationLevel = item.GPOLMProps); + } // Add LDAP properties - _ = enforced.Contains(linkDn) ? (ret.Enforced.LDAPSigning = item.GPOLDAPProps) : (ret.Unenforced.LDAPSigning = item.GPOLDAPProps); + foreach (var i in item.GPOLDAPProps) + { + _ = enforced.Contains(linkDn) ? (ret.Enforced.LDAPSigning[i.Key] = i.Value) : (ret.Unenforced.LDAPSigning[i.Key] = i.Value); + } + + // Add MSCache properties + foreach (var i in item.GPOMSCache) + { + _ = enforced.Contains(linkDn) ? (ret.Enforced.MSCache = item.GPOMSCache) : (ret.Unenforced.MSCache = item.GPOMSCache); + } } } @@ -240,7 +258,6 @@ public async Task ReadGPOLocalGroups(string gpLink, string //If there are no actions, then we can skip some instructions if (actions.Count != 0) { - //First lets process restricted members var restrictedMemberSets = actions.Where(x => x.Target == GroupActionTarget.RestrictedMember) .GroupBy(x => x.TargetRid); @@ -467,6 +484,7 @@ internal async IAsyncEnumerable ProcessGPOTemplateFile(string ba ret.GPOLDAPProps = new Dictionary(); ret.GPOSMBProps = new Dictionary(); ret.GPOLMProps = new Dictionary(); + ret.GPOMSCache = new Dictionary(); // check for registries var regMatch = RegistryRegex.Match(content); @@ -478,9 +496,11 @@ internal async IAsyncEnumerable ProcessGPOTemplateFile(string ba bool EnablesClientSMB = false; bool RequiresLDAPSigning = false; + bool LDAPEnforceChannelBinding = false; - int LmCompatibilityLevel = 3; // default value for W10 = 3 according to https://docs.microsoft.com/fr-fr/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level + int LmCompatibilityLevel = 3; + int CachedLogonsCount = 0; // if registry section is found if (regMatch.Success) @@ -498,9 +518,11 @@ internal async IAsyncEnumerable ProcessGPOTemplateFile(string ba var smbEnableClientMatchLine = SMBEnableClientRegex.Match(regLine); var ldapClientMatchLine = LDAPClientIntegrityRegex.Match(regLine); + var ldapChannelBindingLine = LDAPEnforceChannelBindingRegex.Match(regLine); var lmMatchLine = LMLevelRegex.Match(regLine); + var cachedLogonsLine = CachedLogonsCountRegex.Match(regLine); // if a match is found for this registry if (smbRequireServerMatchLine.Success) @@ -600,6 +622,35 @@ internal async IAsyncEnumerable ProcessGPOTemplateFile(string ba ret.GPOLDAPProps.Add("RequiresLDAPClientSigning", RequiresLDAPSigning); } + else if (ldapChannelBindingLine.Success) + { + var keyMatch = KeyRegex.Match(regLine); + var key = keyMatch.Value.Split(',')[1]; + + switch (key) + { + case "2": // Always enabled + LDAPEnforceChannelBinding = true; + break; + case "1": // Enabled, if supported + LDAPEnforceChannelBinding = false; + break; + case "0": // Disabled + LDAPEnforceChannelBinding = false; + break; + } + + ret.GPOLDAPProps.Add("LDAPEnforceChannelBinding", LDAPEnforceChannelBinding); + } + else if (cachedLogonsLine.Success) + { + var keyMatch = KeyRegex.Match(regLine); + var key = keyMatch.Value.Split(',')[1]; + CachedLogonsCount = Int32.Parse(key.Substring(1, key.Length - 2)); + + ret.GPOMSCache.Add("CachedLogonsCount", CachedLogonsCount); + + } } } @@ -942,6 +993,15 @@ internal enum GroupActionTarget LocalGroup } + internal enum LocalGroupRids + { + None = 0, + Administrators = 544, + RemoteDesktopUsers = 555, + DcomUsers = 562, + PSRemote = 580 + } + internal class GPOReturnTuple { public Dictionary passwordPolicies = new(); @@ -949,6 +1009,7 @@ internal class GPOReturnTuple public Dictionary GPOLDAPProps = new(); public Dictionary GPOSMBProps = new(); public Dictionary GPOLMProps = new(); + public Dictionary GPOMSCache = new(); public GroupAction GPOGroupAction = new(); public bool ContainsGroupAction()