From 8edfc196df02220bdfa73d79398adb6b39c6674e Mon Sep 17 00:00:00 2001 From: pixis Date: Sat, 3 Feb 2024 14:28:22 -0800 Subject: [PATCH 1/2] Add NTLMv1 flag on GPO --- src/CommonLib/OutputTypes/GPO.cs | 1 + .../GPOLmCompatibilityLevelProcessor.cs | 94 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs diff --git a/src/CommonLib/OutputTypes/GPO.cs b/src/CommonLib/OutputTypes/GPO.cs index 081f2975..539e9e74 100644 --- a/src/CommonLib/OutputTypes/GPO.cs +++ b/src/CommonLib/OutputTypes/GPO.cs @@ -2,5 +2,6 @@ { public class GPO : OutputBase { + public bool NTLMv1Enabled { get; set; } } } \ No newline at end of file diff --git a/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs b/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs new file mode 100644 index 00000000..b8de80b1 --- /dev/null +++ b/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.DirectoryServices.Protocols; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml.XPath; +using Microsoft.Extensions.Logging; +using SharpHoundCommonLib.Enums; +using SharpHoundCommonLib.LDAPQueries; +using SharpHoundCommonLib.OutputTypes; + +namespace SharpHoundCommonLib.Processors +{ + public class GPOLmCompatibilityLevelProcessor + { + private static readonly Regex NTLMv1Regex = new Regex(@"\\LmCompatibilityLevel *= *\d+ *, *(\d)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase); + + private readonly ILogger _log; + + private readonly ILDAPUtils _utils; + + public GPOLmCompatibilityLevelProcessor(ILDAPUtils utils, ILogger log = null) + { + _utils = utils; + _log = log ?? Logging.LogProvider.CreateLogger("GPOLmCompatProc"); + } + + public Task ReadGPOLmCompatibilityLevel(ISearchResultEntry entry) + { + var dn = entry.DistinguishedName; + return ReadGPOLmCompatibilityLevel(dn); + } + + public async Task ReadGPOLmCompatibilityLevel(string gpDn) + { + var opts = new LDAPQueryOptions + { + Filter = new LDAPFilter().AddAllObjects().GetFilter(), + Scope = SearchScope.Base, + Properties = CommonProperties.GPCFileSysPath, + AdsPath = gpDn + }; + var filePath = _utils.QueryLDAP(opts).FirstOrDefault()? + .GetProperty(LDAPProperties.GPCFileSYSPath); + if (filePath == null) + { + _log.LogWarning("Unable to process {} for NTLMv1 flag", gpDn); + return false; + } + + + //Add the actions for each file. The GPO template file actions will override the XML file actions + return await ProcessGPOTemplateFile(filePath); + } + + /// + /// Parses a GPO GptTmpl.inf file and pulls group membership changes out + /// + /// + /// + /// + internal async Task ProcessGPOTemplateFile(string basePath) + { + var templatePath = Path.Combine(basePath, "MACHINE", "Microsoft", "Windows NT", "SecEdit", "GptTmpl.inf"); + + if (!File.Exists(templatePath)) + return false; + + FileStream fs; + try + { + fs = new FileStream(templatePath, FileMode.Open, FileAccess.Read); + } + catch + { + return false; + } + + using var reader = new StreamReader(fs); + var content = await reader.ReadToEndAsync(); + var ntlmv1Match = NTLMv1Regex.Match(content); + + if (!ntlmv1Match.Success) + return false; + + //We've got a match! Lets figure out whats going on + var ntlmv1Text = int.Parse(ntlmv1Match.Groups[1].Value); + return ntlmv1Text < 3; + } + } +} \ No newline at end of file From 0cb98e0dff76fb5cfd62ad266c8e8fdce4e6c160 Mon Sep 17 00:00:00 2001 From: pixis Date: Sat, 3 Feb 2024 14:38:10 -0800 Subject: [PATCH 2/2] Code cleanup --- .../Processors/GPOLmCompatibilityLevelProcessor.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs b/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs index b8de80b1..49995f02 100644 --- a/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs +++ b/src/CommonLib/Processors/GPOLmCompatibilityLevelProcessor.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.DirectoryServices.Protocols; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Xml.XPath; using Microsoft.Extensions.Logging; -using SharpHoundCommonLib.Enums; using SharpHoundCommonLib.LDAPQueries; -using SharpHoundCommonLib.OutputTypes; namespace SharpHoundCommonLib.Processors { @@ -51,17 +46,16 @@ public async Task ReadGPOLmCompatibilityLevel(string gpDn) return false; } - - //Add the actions for each file. The GPO template file actions will override the XML file actions return await ProcessGPOTemplateFile(filePath); } /// - /// Parses a GPO GptTmpl.inf file and pulls group membership changes out + /// Parses a GPO GptTmpl.inf file and grep lmcompatibilitylevel value /// /// - /// - /// + /// + /// lmcompatibilitylevel < 3 + /// internal async Task ProcessGPOTemplateFile(string basePath) { var templatePath = Path.Combine(basePath, "MACHINE", "Microsoft", "Windows NT", "SecEdit", "GptTmpl.inf");