Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ The listing below details the CLI arguments SharpHound supports. Additional deta

--collectallproperties Collect all LDAP properties from objects

--skipdenyacescount Skip collecting custom deny ACE counts in LDAP object properties

-l, --Loop Loop computer collection

--loopduration Loop duration (hh:mm:ss - 05:00:00 is 5 hours, default: 2 hrs)
Expand Down
3 changes: 2 additions & 1 deletion src/Client/Flags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class Flags
public bool NoRegistryLoggedOn { get; set; }
public bool DumpComputerStatus { get; set; }
public bool CollectAllProperties { get; set; }
public bool SkipDenyAcesCount { get; set; }
public bool DCOnly { get; set; }
public bool PrettyPrint { get; set; }
public bool SearchForest { get; set; }
Expand All @@ -30,4 +31,4 @@ public class Flags
public bool ParititonLdapQueries { get; set; }
public bool Metrics { get; set; }
}
}
}
3 changes: 3 additions & 0 deletions src/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ public class Options

[Option(HelpText = "Collect all LDAP properties from objects")]
public bool CollectAllProperties { get; set; }

[Option(HelpText = "Skip collecting custom deny ACE counts in LDAP object properties")]
public bool SkipDenyAcesCount { get; set; }

[Option(HelpText = "Split the main ldap query into smaller chunks to attempt to reduce server load")]
public bool PartitionLdapQueries { get; set; }
Expand Down
7 changes: 7 additions & 0 deletions src/PowerShell/Template.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@
.PARAMETER CollectAllProperties

Collect all string LDAP properties on objects

.PARAMETER SkipDenyAcesCount

Skip collecting custom deny ACE counts in LDAP object properties

.PARAMETER Loop

Expand Down Expand Up @@ -360,6 +364,9 @@
[Switch]
$CollectAllProperties,

[Switch]
$SkipDenyAcesCount,

[Switch]
$Loop,

Expand Down
65 changes: 38 additions & 27 deletions src/Runtime/ObjectProcessors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
namespace Sharphound.Runtime {
public class ObjectProcessors {
private const string StatusSuccess = "Success";
private const string CustomExplicitDenyAcesCountProperty = "customexplicitdenyacescount";
private const string CustomInheritedDenyAcesCountProperty = "custominheriteddenyacescount";
private readonly ACLProcessor _aclProcessor;
private readonly CertAbuseProcessor _certAbuseProcessor;
private readonly CancellationToken _cancellationToken;
Expand Down Expand Up @@ -165,6 +167,28 @@
return null;
}

private async Task<ACE[]> ProcessACL(IDirectoryObject entry, ResolvedSearchResult resolvedSearchResult,
Dictionary<string, object> properties) {
if (_context.Flags.SkipDenyAcesCount) {
return await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
}

var result = await _aclProcessor.ProcessACLWithCustomDenyAces(resolvedSearchResult, entry);
AddCustomDenyAceCounts(properties, result.CustomDenyAceCounts);
return result.Aces;
}

private static void AddCustomDenyAceCounts(Dictionary<string, object> properties,
ACLProcessor.CustomDenyAceCounts counts) {

Check failure on line 183 in src/Runtime/ObjectProcessors.cs

View workflow job for this annotation

GitHub Actions / build

The type name 'CustomDenyAceCounts' does not exist in the type 'ACLProcessor'

Check failure on line 183 in src/Runtime/ObjectProcessors.cs

View workflow job for this annotation

GitHub Actions / build

The type name 'CustomDenyAceCounts' does not exist in the type 'ACLProcessor'
if (counts.Total == 0) {
return;
}

properties[CustomExplicitDenyAcesCountProperty] = counts.ExplicitCount;
properties[CustomInheritedDenyAcesCountProperty] = counts.InheritedCount;
}

private async Task<User> ProcessUserObject(IDirectoryObject entry,
ResolvedSearchResult resolvedSearchResult)
{
Expand All @@ -185,8 +209,7 @@
// AdminSDHolderProtected only on security principal nodes: User, Computer, Group
var adminSdHolderHash = GetAdminSdHolderHash(resolvedSearchResult.Domain);

var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
var gmsa = entry.GetByteProperty(LDAPProperties.GroupMSAMembership);
Expand Down Expand Up @@ -262,8 +285,7 @@
// AdminSDHolderProtected only on security principal nodes: User, Computer, Group
var adminSdHolderHash = GetAdminSdHolderHash(resolvedSearchResult.Domain);

var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -475,8 +497,7 @@
// AdminSDHolderProtected only on security principal nodes: User, Computer, Group
var adminSdHolderHash = GetAdminSdHolderHash(resolvedSearchResult.Domain);

var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -528,8 +549,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Aces = aces;
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
Expand Down Expand Up @@ -571,8 +591,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -600,8 +619,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -650,8 +668,7 @@
}

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -683,8 +700,7 @@


if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -714,8 +730,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -744,8 +759,7 @@
};

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -861,8 +875,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -900,8 +913,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand Down Expand Up @@ -932,8 +944,7 @@
ret.Properties = new Dictionary<string, object>(GetCommonProperties(entry, resolvedSearchResult));

if (_methods.HasFlag(CollectionMethod.ACL) || _methods.HasFlag(CollectionMethod.CertServices)) {
var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true)
.ToArrayAsync(cancellationToken: _cancellationToken);
var aces = await ProcessACL(entry, resolvedSearchResult, ret.Properties);
ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid));
ret.Properties.Add("doesanyinheritedacegrantownerrights", aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid));
ret.Aces = aces;
Expand All @@ -956,4 +967,4 @@
return ret;
}
}
}
}
3 changes: 2 additions & 1 deletion src/Sharphound.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ await options.WithParsedAsync(async options =>
RandomizeFilenames = options.RandomFileNames,
MemCache = options.MemCache,
CollectAllProperties = options.CollectAllProperties,
SkipDenyAcesCount = options.SkipDenyAcesCount,
DCOnly = dconly,
PrettyPrint = options.PrettyPrint,
SearchForest = options.SearchForest,
Expand Down Expand Up @@ -264,4 +265,4 @@ public static void InvokeSharpHound(string[] args) {
}

#endregion
}
}
Loading