Skip to content

Commit 8edfc19

Browse files
committed
Add NTLMv1 flag on GPO
1 parent ab2e21a commit 8edfc19

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

src/CommonLib/OutputTypes/GPO.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
{
33
public class GPO : OutputBase
44
{
5+
public bool NTLMv1Enabled { get; set; }
56
}
67
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.DirectoryServices.Protocols;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Text.RegularExpressions;
8+
using System.Threading.Tasks;
9+
using System.Xml.XPath;
10+
using Microsoft.Extensions.Logging;
11+
using SharpHoundCommonLib.Enums;
12+
using SharpHoundCommonLib.LDAPQueries;
13+
using SharpHoundCommonLib.OutputTypes;
14+
15+
namespace SharpHoundCommonLib.Processors
16+
{
17+
public class GPOLmCompatibilityLevelProcessor
18+
{
19+
private static readonly Regex NTLMv1Regex = new Regex(@"\\LmCompatibilityLevel *= *\d+ *, *(\d)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
20+
21+
private readonly ILogger _log;
22+
23+
private readonly ILDAPUtils _utils;
24+
25+
public GPOLmCompatibilityLevelProcessor(ILDAPUtils utils, ILogger log = null)
26+
{
27+
_utils = utils;
28+
_log = log ?? Logging.LogProvider.CreateLogger("GPOLmCompatProc");
29+
}
30+
31+
public Task<Boolean> ReadGPOLmCompatibilityLevel(ISearchResultEntry entry)
32+
{
33+
var dn = entry.DistinguishedName;
34+
return ReadGPOLmCompatibilityLevel(dn);
35+
}
36+
37+
public async Task<Boolean> ReadGPOLmCompatibilityLevel(string gpDn)
38+
{
39+
var opts = new LDAPQueryOptions
40+
{
41+
Filter = new LDAPFilter().AddAllObjects().GetFilter(),
42+
Scope = SearchScope.Base,
43+
Properties = CommonProperties.GPCFileSysPath,
44+
AdsPath = gpDn
45+
};
46+
var filePath = _utils.QueryLDAP(opts).FirstOrDefault()?
47+
.GetProperty(LDAPProperties.GPCFileSYSPath);
48+
if (filePath == null)
49+
{
50+
_log.LogWarning("Unable to process {} for NTLMv1 flag", gpDn);
51+
return false;
52+
}
53+
54+
55+
//Add the actions for each file. The GPO template file actions will override the XML file actions
56+
return await ProcessGPOTemplateFile(filePath);
57+
}
58+
59+
/// <summary>
60+
/// Parses a GPO GptTmpl.inf file and pulls group membership changes out
61+
/// </summary>
62+
/// <param name="basePath"></param>
63+
/// <param name="gpoDomain"></param>
64+
/// <returns></returns>
65+
internal async Task<Boolean> ProcessGPOTemplateFile(string basePath)
66+
{
67+
var templatePath = Path.Combine(basePath, "MACHINE", "Microsoft", "Windows NT", "SecEdit", "GptTmpl.inf");
68+
69+
if (!File.Exists(templatePath))
70+
return false;
71+
72+
FileStream fs;
73+
try
74+
{
75+
fs = new FileStream(templatePath, FileMode.Open, FileAccess.Read);
76+
}
77+
catch
78+
{
79+
return false;
80+
}
81+
82+
using var reader = new StreamReader(fs);
83+
var content = await reader.ReadToEndAsync();
84+
var ntlmv1Match = NTLMv1Regex.Match(content);
85+
86+
if (!ntlmv1Match.Success)
87+
return false;
88+
89+
//We've got a match! Lets figure out whats going on
90+
var ntlmv1Text = int.Parse(ntlmv1Match.Groups[1].Value);
91+
return ntlmv1Text < 3;
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)