Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADCS Data collection consistency fixes #84

Merged
merged 13 commits into from
Jan 19, 2024
Merged
3 changes: 3 additions & 0 deletions src/BaseContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -64,6 +65,8 @@ public void UpdateLoopTime()
CurrentLoopTime = $"{DateTime.Now:yyyyMMddHHmmss}";
}

public HashSet<string> CollectedDomainSids { get; } = new();

public async Task DoDelay()
{
if (Throttle == 0)
Expand Down
1 change: 1 addition & 0 deletions src/Client/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@ public interface IContext
string ResolveFileName(string filename, string extension, bool addTimestamp);
EnumerationDomain[] Domains { get; set; }
void UpdateLoopTime();
public HashSet<string> CollectedDomainSids { get; }
}
}
5 changes: 4 additions & 1 deletion src/Producers/BaseProducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ protected LDAPData CreateDefaultNCData()

if ((methods & ResolvedCollectionMethod.DCRegistry) != 0)
{
query = query.AddComputers();
query = query.AddComputers(CommonFilters.DomainControllers);
props.AddRange(CommonProperties.ComputerMethodProps);
}
}
Expand Down Expand Up @@ -169,6 +169,9 @@ protected LDAPData CreateConfigNCData()
{
query = allObjectTypesQuery;
props.AddRange(CommonProperties.CertAbuseProps);
props.AddRange(CommonProperties.ObjectPropsProps);
props.AddRange(CommonProperties.ContainerProps);
props.AddRange(CommonProperties.ACLProps);
}

if ((methods & ResolvedCollectionMethod.Container) != 0)
Expand Down
24 changes: 10 additions & 14 deletions src/Producers/LdapProducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public override async Task Produce()
var log = Context.Logger;
var utils = Context.LDAPUtils;

if (string.IsNullOrEmpty(ldapData.Filter.GetFilter()))
{
return;
}

if (Context.Flags.CollectAllProperties)
{
log.LogDebug("CollectAllProperties set. Changing LDAP properties to *");
Expand All @@ -39,7 +44,7 @@ public override async Task Produce()

foreach (var domain in Context.Domains)
{
Context.Logger.LogInformation("Beginning LDAP search for {Domain}", domain);
Context.Logger.LogInformation("Beginning LDAP search for {Domain}", domain.Name);
//Do a basic LDAP search and grab results
var successfulConnect = false;
try
Expand All @@ -59,14 +64,7 @@ public override async Task Produce()
continue;
}

await OutputChannel.Writer.WriteAsync(new Domain
{
ObjectIdentifier = domain.DomainSid,
Properties = new Dictionary<string, object>
{
{ "collected", true },
}
});
Context.CollectedDomainSids.Add(domain.DomainSid);

foreach (var searchResult in Context.LDAPUtils.QueryLDAP(ldapData.Filter.GetFilter(), SearchScope.Subtree,
ldapData.Props.Distinct().ToArray(), cancellationToken, domain.Name,
Expand All @@ -83,7 +81,6 @@ await OutputChannel.Writer.WriteAsync(new Domain
Context.Logger.LogTrace("Producer wrote {DistinguishedName} to channel", searchResult.DistinguishedName);
}
}

}

/// <summary>
Expand All @@ -105,19 +102,18 @@ public override async Task ProduceConfigNC()
if (!configurationNCsCollected.Contains(configAdsPath))
{
Context.Logger.LogInformation("Beginning LDAP search for {Domain} Configuration NC", domain.Name);
// Ensure we only collect the Configuration NC once per forest
configurationNCsCollected.Add(configAdsPath);

//Do a basic LDAP search and grab results
foreach (var searchResult in Context.LDAPUtils.QueryLDAP(configNcData.Filter.GetFilter(), SearchScope.Subtree,
configNcData.Props.Distinct().ToArray(), cancellationToken, domain.Name,
adsPath: configAdsPath,
includeAcl: (Context.ResolvedCollectionMethods & ResolvedCollectionMethod.ACL) != 0))
includeAcl: (Context.ResolvedCollectionMethods & ResolvedCollectionMethod.ACL) != 0 || (Context.ResolvedCollectionMethods & ResolvedCollectionMethod.CertServices) != 0))
{
await Channel.Writer.WriteAsync(searchResult, cancellationToken);
Context.Logger.LogTrace("Producer wrote {DistinguishedName} to channel", searchResult.DistinguishedName);
}

// Ensure we only collect the Configuration NC once per forest
configurationNCsCollected.Add(configAdsPath);
}
else
{
Expand Down
13 changes: 13 additions & 0 deletions src/Runtime/CollectionTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class CollectionTask
private readonly OutputWriter _outputWriter;
private readonly BaseProducer _producer;
private readonly List<Task> _taskPool = new();
private const string EnterpriseDCSuffix = "S-1-5-9";

public CollectionTask(IContext context)
{
Expand Down Expand Up @@ -82,7 +83,19 @@ internal async Task<string> StartCollection()
_log.LogInformation("Consumers finished, closing output channel");

foreach (var wkp in _context.LDAPUtils.GetWellKnownPrincipalOutput(_context.DomainName))
{
if (!wkp.ObjectIdentifier.EndsWith(EnterpriseDCSuffix))
{
wkp.Properties["reconcile"] = false;
}
else if (wkp is Group g && g.Members.Length == 0)
{
continue;
}
rvazarkar marked this conversation as resolved.
Show resolved Hide resolved

await _outputChannel.Writer.WriteAsync(wkp);
}


_outputChannel.Writer.Complete();
_compStatusChannel?.Writer.Complete();
Expand Down
5 changes: 5 additions & 0 deletions src/Runtime/LDAPConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ internal static async Task ConsumeSearchResults(Channel<ISearchResultEntry> inpu
watch.Elapsed.TotalMilliseconds, res.DisplayName);
if (processed == null)
continue;

if (processed is Domain d && context.CollectedDomainSids.Contains(d.ObjectIdentifier))
{
d.Properties.Add("collected", true);
}
await outputChannel.Writer.WriteAsync(processed);
}
catch (Exception e)
Expand Down
Loading
Loading