-
Notifications
You must be signed in to change notification settings - Fork 55
Expand file tree
/
Copy pathGPOLmCompatibilityLevelProcessor.cs
More file actions
88 lines (75 loc) · 2.88 KB
/
GPOLmCompatibilityLevelProcessor.cs
File metadata and controls
88 lines (75 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.DirectoryServices.Protocols;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SharpHoundCommonLib.LDAPQueries;
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<Boolean> ReadGPOLmCompatibilityLevel(ISearchResultEntry entry)
{
var dn = entry.DistinguishedName;
return ReadGPOLmCompatibilityLevel(dn);
}
public async Task<Boolean> 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;
}
return await ProcessGPOTemplateFile(filePath);
}
/// <summary>
/// Parses a GPO GptTmpl.inf file and grep lmcompatibilitylevel value
/// </summary>
/// <param name="basePath"></param>
/// <returns>
/// lmcompatibilitylevel < 3
/// </returns>
internal async Task<Boolean> 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;
}
}
}