Skip to content
3 changes: 2 additions & 1 deletion src/CommonLib/Enums/CollectionMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ public enum CollectionMethod {
WebClientService = 1 << 21,
SmbInfo = 1 << 22,
NTLMRegistry = 1 << 23,
Site = 1 << 24,
//TODO: Re-introduce this when we're ready for Event Log collection
//EventLogs = 1 << 23,
LocalGroups = DCOM | RDP | LocalAdmin | PSRemote,
ComputerOnly = LocalGroups | Session | UserRights | CARegistry | DCRegistry | WebClientService | SmbInfo | NTLMRegistry,
DCOnly = ACL | Container | Group | ObjectProps | Trusts | GPOLocalGroup | CertServices,

Default = Group | Session | Trusts | ACL | ObjectProps | LocalGroups | SPNTargets | Container | CertServices |
LdapServices | SmbInfo | WebClientService,
LdapServices | SmbInfo | WebClientService | Site,

All = Default | LoggedOn | GPOLocalGroup | UserRights | CARegistry | DCRegistry | WebClientService |
LdapServices | NTLMRegistry
Expand Down
3 changes: 3 additions & 0 deletions src/CommonLib/Enums/DataType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ public static class DataType
public const string EnterpriseCAs = "enterprisecas";
public const string CertTemplates = "certtemplates";
public const string IssuancePolicies = "issuancepolicies";
public const string Sites = "sites";
public const string SiteServers = "siteservers";
public const string SiteSubnets = "sitesubnets";
}
}
2 changes: 2 additions & 0 deletions src/CommonLib/Enums/LDAPProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,7 @@ public static class LDAPProperties
public const string LockOutObservationWindow = "lockoutobservationwindow";
public const string PrincipalName = "msds-principalname";
public const string GroupType = "grouptype";
public const string ServerReference = "serverreference";
public const string SiteObject = "siteobject";
}
}
5 changes: 4 additions & 1 deletion src/CommonLib/Enums/Labels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public enum Label
AIACA,
EnterpriseCA,
NTAuthStore,
IssuancePolicy
IssuancePolicy,
Site,
SiteServer,
SiteSubnet
}
}
3 changes: 3 additions & 0 deletions src/CommonLib/Enums/ObjectClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ public static class ObjectClass {
public const string OIDContainerClass = "msPKI-Enterprise-Oid";
public const string GMSAClass = "msds-groupmanagedserviceaccount";
public const string MSAClass = "msds-managedserviceaccount";
public const string SiteClass = "site";
public const string SiteServerClass = "server";
public const string SiteSubnetClass = "subnet";
}
12 changes: 10 additions & 2 deletions src/CommonLib/LdapProducerQueryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@ public static GeneratedLdapParameters GenerateConfigurationPartitionParameters(C
properties.AddRange(CommonProperties.TypeResolutionProps);

if (methods.HasFlag(CollectionMethod.ACL) || methods.HasFlag(CollectionMethod.ObjectProps) ||
methods.HasFlag(CollectionMethod.Container) || methods.HasFlag(CollectionMethod.CertServices)) {
methods.HasFlag(CollectionMethod.Container) || methods.HasFlag(CollectionMethod.CertServices) ||
methods.HasFlag(CollectionMethod.Site)) {
filter = filter.AddContainers().AddConfiguration().AddCertificateTemplates().AddCertificateAuthorities()
.AddEnterpriseCertificationAuthorities().AddIssuancePolicies();
.AddEnterpriseCertificationAuthorities().AddIssuancePolicies().AddSites().AddSiteServers().AddSiteSubnets();

if (methods.HasFlag(CollectionMethod.ObjectProps)) {
properties.AddRange(CommonProperties.ObjectPropsProps);
Expand All @@ -131,6 +132,13 @@ public static GeneratedLdapParameters GenerateConfigurationPartitionParameters(C
properties.AddRange(CommonProperties.CertAbuseProps);
}

if (methods.HasFlag(CollectionMethod.Site))
{
properties.AddRange(CommonProperties.SiteProps);
properties.AddRange(CommonProperties.SiteServerProps);
properties.AddRange(CommonProperties.SiteSubnetProps);
}

return new GeneratedLdapParameters {
Filter = filter,
Attributes = properties.Distinct().ToArray()
Expand Down
18 changes: 18 additions & 0 deletions src/CommonLib/LdapQueries/CommonProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,23 @@ public static class CommonProperties
public static readonly string[] StealthProperties = {
LDAPProperties.HomeDirectory, LDAPProperties.ScriptPath, LDAPProperties.ProfilePath
};

public static readonly string[] SiteProps =
{
LDAPProperties.DisplayName, LDAPProperties.Name, LDAPProperties.ObjectGUID, LDAPProperties.GPLink,
LDAPProperties.GroupPolicyOptions, LDAPProperties.ObjectClass
};

public static readonly string[] SiteServerProps =
{
LDAPProperties.DisplayName, LDAPProperties.Name, LDAPProperties.ObjectGUID, LDAPProperties.ObjectClass, LDAPProperties.DNSHostName,
LDAPProperties.ServerReference
};

public static readonly string[] SiteSubnetProps =
{
LDAPProperties.DisplayName, LDAPProperties.Name, LDAPProperties.CanonicalName, LDAPProperties.ObjectGUID, LDAPProperties.ObjectClass,
LDAPProperties.SiteObject
};
}
}
39 changes: 39 additions & 0 deletions src/CommonLib/LdapQueries/LdapFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,45 @@ public LdapFilter AddComputersNoMSAs(params string[] conditions) {
return this;
}

/// <summary>
/// Add a filter that will match Active Directory sites
/// </summary>
/// <param name="conditions"></param>
/// <returns></returns>
public LdapFilter AddSites(params string[] conditions)
{
_filterParts.Add(BuildString(
"(objectClass=site)",
conditions));
return this;
}

/// <summary>
/// Add a filter that will match Active Directory site servers
/// </summary>
/// <param name="conditions"></param>
/// <returns></returns>
public LdapFilter AddSiteServers(params string[] conditions)
{
_filterParts.Add(BuildString(
"(objectClass=server)",
conditions));
return this;
}

/// <summary>
/// Add a filter that will match Active Directory site subnets
/// </summary>
/// <param name="conditions"></param>
/// <returns></returns>
public LdapFilter AddSiteSubnets(params string[] conditions)
{
_filterParts.Add(BuildString(
"(objectClass=subnet)",
conditions));
return this;
}

/// <summary>
/// Adds a generic user specified filter
/// </summary>
Expand Down
54 changes: 51 additions & 3 deletions src/CommonLib/LdapUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,18 @@ internal static bool ResolveLabel(string objectIdentifier, string distinguishedN
type = Label.IssuancePolicy;
}
}
else if (objectClasses.Contains(ObjectClass.SiteClass, StringComparer.OrdinalIgnoreCase))
{
type = Label.Site;
}
else if (objectClasses.Contains(ObjectClass.SiteServerClass, StringComparer.OrdinalIgnoreCase))
{
type = Label.SiteServer;
}
else if (objectClasses.Contains(ObjectClass.SiteSubnetClass, StringComparer.OrdinalIgnoreCase))
{
type = Label.SiteSubnet;
}

return type != Label.Base;
}
Expand All @@ -1214,7 +1226,7 @@ internal static bool ResolveLabel(string objectIdentifier, string distinguishedN
if (!directoryObject.GetObjectIdentifier(out var objectIdentifier)) {
return (false, default);
}

var res = new ResolvedSearchResult {
ObjectId = objectIdentifier
};
Expand Down Expand Up @@ -1270,11 +1282,10 @@ await utils.GetDomainNameFromSid(objectIdentifier) is (true, var domainName)) {
if (await utils.GetWellKnownPrincipal(objectIdentifier, domain) is (true, var convertedPrincipal)) {
res.ObjectId = convertedPrincipal.ObjectIdentifier;
}

return (true, res);
}

res.ObjectType = await ComputeLabel(directoryObject, objectIdentifier, domain, utils);
res.ObjectType = await ComputeLabel(directoryObject, objectIdentifier, domain, utils);

directoryObject.TryGetProperty(LDAPProperties.SAMAccountName, out var samAccountName);
res.DisplayName = ComputeDisplayName(directoryObject, domain, res.ObjectType, samAccountName);
Expand Down Expand Up @@ -1395,6 +1406,43 @@ private static string ComputeDisplayName(IDirectoryObject directoryObject, strin
displayName = $"UNKNOWN@{domain}";
}

break;
}
case Label.Site: {
if (directoryObject.TryGetProperty(LDAPProperties.Name, out var name))
{
displayName = $"{name}@{domain}";
}
else
{
displayName = $"UNKNOWN@{domain}";
}
break;
}
case Label.SiteServer:
{
// Not specifying @{domain} here since Site servers may belong to other domains, so this might confuse the user
if (directoryObject.TryGetProperty(LDAPProperties.Name, out var name))
{
displayName = $"{name}";
}
else
{
displayName = $"UNKNOWN";
}
break;
}
case Label.SiteSubnet:
{
// Not specifying @{domain} here since subnets are not domain-specific
if (directoryObject.TryGetProperty(LDAPProperties.Name, out var name))
{
displayName = $"{name}";
}
else
{
displayName = $"UNKNOWN";
}
break;
}
default:
Expand Down
12 changes: 12 additions & 0 deletions src/CommonLib/OutputTypes/Site.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace SharpHoundCommonLib.OutputTypes
{
public class Site : OutputBase
{
// Subnets and Servers are common site children; keep them optional and empty by default.
//public string[] Subnets { get; set; } = Array.Empty<string>();
//public TypedPrincipal[] Servers { get; set; } = Array.Empty<TypedPrincipal>();
public GPLink[] Links { get; set; } = Array.Empty<GPLink>();
}
}
7 changes: 7 additions & 0 deletions src/CommonLib/OutputTypes/SiteServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SharpHoundCommonLib.OutputTypes
{
public class SiteServer : OutputBase
{

}
}
7 changes: 7 additions & 0 deletions src/CommonLib/OutputTypes/SiteSubnet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SharpHoundCommonLib.OutputTypes
{
public class SiteSubnet : OutputBase
{

}
}
12 changes: 9 additions & 3 deletions src/CommonLib/Processors/ACLProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ static ACLProcessor() {
{ Label.EnterpriseCA, "ee4aa692-3bba-11d2-90cc-00c04fd91ab1" },
{ Label.NTAuthStore, "3fdfee50-47f4-11d1-a9c3-0000f80367c1" },
{ Label.CertTemplate, "e5209ca2-3bba-11d2-90cc-00c04fd91ab1" },
{ Label.IssuancePolicy, "37cfd85c-6719-4ad8-8f9e-8678ba627563" }
{ Label.IssuancePolicy, "37cfd85c-6719-4ad8-8f9e-8678ba627563" },
{ Label.Site, "bf967ab3-0de6-11d0-a285-00aa003049e2" },
{ Label.SiteServer, "bf967a92-0de6-11d0-a285-00aa003049e2" },
{ Label.SiteSubnet, "b7b13124-b82e-11d0-afee-0000f80367c1" }
};
}

Expand Down Expand Up @@ -734,7 +737,10 @@ or Label.RootCA
or Label.EnterpriseCA
or Label.AIACA
or Label.NTAuthStore
or Label.IssuancePolicy)
or Label.IssuancePolicy
or Label.Site
or Label.SiteServer
or Label.SiteSubnet)
if (aceType is ACEGuids.AllGuid or "")
yield return new ACE {
PrincipalType = resolvedPrincipal.ObjectType,
Expand Down Expand Up @@ -776,7 +782,7 @@ or Label.NTAuthStore
IsPermissionForOwnerRightsSid = isPermissionForOwnerRightsSid,
IsInheritedPermissionForOwnerRightsSid = isInheritedPermissionForOwnerRightsSid,
};
else if (objectType is Label.OU or Label.Domain && aceType == ACEGuids.WriteGPLink)
else if (objectType is Label.OU or Label.Domain or Label.Site && aceType == ACEGuids.WriteGPLink)
yield return new ACE {
PrincipalType = resolvedPrincipal.ObjectType,
PrincipalSID = resolvedPrincipal.ObjectIdentifier,
Expand Down
23 changes: 23 additions & 0 deletions src/CommonLib/Processors/LdapPropertyProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,29 @@ public async Task<IssuancePolicyProperties> ReadIssuancePolicyProperties(IDirect
return ret;
}

public static Dictionary<string, object> ReadSiteProperties(IDirectoryObject entry)
{
var props = GetCommonProps(entry);
return props;
}


public static Dictionary<string, object> ReadSiteServerProperties(IDirectoryObject entry)
{
var props = GetCommonProps(entry);
props.Add("dnshostname", entry.GetProperty(LDAPProperties.DNSHostName));
props.Add("serverreference", entry.GetProperty(LDAPProperties.ServerReference));
return props;
}

public static Dictionary<string, object> ReadSiteSubnetProperties(IDirectoryObject entry)
{
var props = GetCommonProps(entry);
props.Add("cn", entry.GetProperty(LDAPProperties.CanonicalName));
props.Add("siteObject", entry.GetProperty(LDAPProperties.SiteObject));
return props;
}

/// <summary>
/// Attempts to parse all LDAP attributes outside of the ones already collected and converts them to a human readable
/// format using a best guess
Expand Down
Loading