Skip to content

Conversation

@JimSycurity
Copy link
Contributor

@JimSycurity JimSycurity commented Jul 29, 2025

Description

  • Added a dictionary to context to cache AdminSDHolderHash with the corresponding domain
  • If ACL collection is enabled, LdapProducer will:
    • Collect the security descriptor for the AdminSDHolder container for the current domain
    • Hash the authoritative SD using new methods in SHC
    • Cache the hash with the domain in the context
  • If ACL collection is enabled ObjectProcessor will:
    • For user, group, and computer nodes retrieve the AdminSDHolderHash from context for the appropriate domain
    • Call IsAdminSDHolderProtected() to hash the SD of the node and compare it with the AdminSDHolderHash provided
    • Set the 'adminsdholderprotected' property appropriately

Resolves BED-6221

Motivation and Context

This code expands upon the SharpHoundCommon work in SpecterOps/SharpHoundCommon#230 to produce the adminsdholderprotected property on user, computer, and group nodes as part of the AdminSDHolder design which will then enable graph expansion for AdminSDHolder in BloodHound and ultimately better findings in BHE.

In order to determine if an object is AdminSDHolder protected, my research has determined that the most reliable method across all scenarios is to compare the authoritative security descriptor of the AdminSDHolder container for the domain with the authoritative SD of security principals in the domain. When there is a match, the object is effectively protected.

Issue: https://specterops.atlassian.net/browse/BED-6178

This PR should ideally correspond to a BHCE and BHE version update with the graph expansion changes.

How Has This Been Tested?

A build of this code with these changes and the underlying SHC updates was tested in my home lab environment using multiple AD forests configured for AdminSDHolder research.

A SharpHound FOSS build with these changes and the underlying SHC updates was also tested by Jonas in the Dev GOAD Azure lab.

Data from these captures has been ingested into both BHCE and BHE dev instances based on my BED-6178 branches. Data ingestion has been consistent and appropriate.

Screenshots (if appropriate):

image

Types of changes

  • Chore (a change that does not modify the application functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • Documentation updates are needed, and have been made accordingly.
  • I have added and/or updated tests to cover my changes.
  • All new and existing tests passed.
  • My changes include a database migration.

Summary by CodeRabbit

  • New Features
    • Added display of AdminSDHolder protection status for user, computer, and group objects.
  • Enhancements
    • Improved collection and processing of AdminSDHolder security descriptor data for each domain.
  • Bug Fixes
    • Minor formatting and comment adjustments for improved clarity.

- Added AdminSDHolderHash dictionary to contexts
- Collect AdminSDHolder data if ACL collection is enabled in LdapProducer
- Compare SD hash of users, computers, groups with AdminSDHolder hash for that domain to determine status of adminsdholderprotected property

Resolves BED-6221
@JimSycurity JimSycurity self-assigned this Jul 29, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 29, 2025

Walkthrough

A new property, AdminSDHolderHash, was added to both the BaseContext class and the IContext interface to map domain names to AdminSDHolder security descriptor hashes. The LDAP producer logic now collects and stores these hashes, and ACL processing for users, computers, and groups checks this hash to determine AdminSDHolder protection status.

Changes

Cohort / File(s) Change Summary
Context Property Additions
src/BaseContext.cs, src/Client/Context.cs
Added a public property AdminSDHolderHash (dictionary mapping domain names to security descriptor hashes) to BaseContext and the IContext interface.
LDAP Producer Enhancements
src/Producers/LdapProducer.cs
Enhanced the Produce method to collect AdminSDHolder security descriptor hashes when ACL collection is enabled, compute their hashes, store them in the context dictionary, and log the process. The main LDAP query loop was moved after this new block.
ACL Processing Updates
src/Runtime/ObjectProcessors.cs
Updated ACL processing for User, Computer, and Group objects to check and include an "adminsdholderprotected" property, using the domain-specific AdminSDHolder hash from the context. Minor formatting and comment adjustments were also made.
Project File Minor Edit
Sharphound.csproj
Removed trailing newline character at the end of the project file without other content changes.

Sequence Diagram(s)

sequenceDiagram
    participant Producer as LdapProducer
    participant Directory as LDAP Directory
    participant Context as Context
    participant ACLProc as ACLProcessor

    Producer->>Directory: Query AdminSDHolder container (LDAP)
    Directory-->>Producer: Return nTSecurityDescriptor
    Producer->>ACLProc: Compute ACL hash from security descriptor
    ACLProc-->>Producer: Return hash
    Producer->>Context: Store hash in AdminSDHolderHash[domain]
    Producer->>Directory: Continue with main LDAP queries
    Directory-->>Producer: Return objects
    Producer->>Context: Process and output objects
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Suggested labels

blocked by SHC PR

Suggested reviewers

  • ktstrader
  • definitelynotagoblin

Poem

A rabbit hopped through code so neat,
With hashes for holders, a security treat.
Domains now mapped, protection in tow,
LDAP and ACLs in a harmonious flow.
With every new property, carrots abound—
In burrows of logic, new features are found! 🥕

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c60df8e and 7394ed9.

📒 Files selected for processing (3)
  • src/BaseContext.cs (2 hunks)
  • src/Producers/LdapProducer.cs (4 hunks)
  • src/Runtime/ObjectProcessors.cs (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/BaseContext.cs
  • src/Runtime/ObjectProcessors.cs
  • src/Producers/LdapProducer.cs
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jsykora/BED-6178

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@JimSycurity JimSycurity added enhancement New feature or request external This pull request is from an external contributor labels Jul 29, 2025
@JimSycurity JimSycurity marked this pull request as ready for review July 30, 2025 13:18
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/Runtime/ObjectProcessors.cs (1)

427-449: Consider extracting common AdminSDHolder logic

The implementation is correct and consistent with User and Computer processing. However, the AdminSDHolder hash retrieval logic is duplicated across all three methods.

Consider extracting the common logic into a helper method:

+private string GetAdminSDHolderHash(string domain)
+{
+    if (_context.AdminSDHolderHash != null &&
+        _context.AdminSDHolderHash.TryGetValue(domain, out var hash))
+    {
+        return hash;
+    }
+    return null;
+}

Then simplify each occurrence to:

-string adminSdHolderHash = null;
-if (_context.AdminSDHolderHash != null &&
-    _context.AdminSDHolderHash.TryGetValue(resolvedSearchResult.Domain, out var hash))
-{
-    adminSdHolderHash = hash;
-}
+var adminSdHolderHash = GetAdminSDHolderHash(resolvedSearchResult.Domain);
src/Producers/LdapProducer.cs (2)

94-94: Consider reusing ACLProcessor instance

A new ACLProcessor instance is created here, but the ObjectProcessors class already has an _aclProcessor field. Consider if this instance could be reused or injected.


100-102: Initialize AdminSDHolderHash in constructor

The dictionary is initialized on first use. Consider initializing it in the BaseContext constructor for cleaner code.

In BaseContext.cs constructor:

 public BaseContext(ILogger logger, LdapConfig ldapConfig, Flags flags)
 {
     Logger = logger;
     Flags = flags;
     LDAPUtils = new LdapUtils();
     LDAPUtils.SetLdapConfig(ldapConfig);
     CancellationTokenSource = new CancellationTokenSource();
+    AdminSDHolderHash = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45f843c and 4427104.

📒 Files selected for processing (4)
  • src/BaseContext.cs (1 hunks)
  • src/Client/Context.cs (1 hunks)
  • src/Producers/LdapProducer.cs (4 hunks)
  • src/Runtime/ObjectProcessors.cs (6 hunks)
🔇 Additional comments (6)
src/BaseContext.cs (1)

125-128: LGTM!

The property addition is clean and follows the existing code patterns. The XML documentation clearly describes its purpose.

src/Client/Context.cs (1)

80-84: LGTM!

The interface extension is properly documented and consistent with the implementation in BaseContext.cs.

src/Runtime/ObjectProcessors.cs (2)

137-161: LGTM!

The AdminSDHolder protection check is properly implemented with appropriate null checks and only executes when ACL collection is enabled.


214-236: Good consistency with User processing

The implementation correctly mirrors the User object processing, maintaining consistency across security principal types.

src/Producers/LdapProducer.cs (2)

58-75: LGTM!

The AdminSDHolder query setup is correct with appropriate attributes and security descriptor inclusion.


111-124: Good error handling

The error handling appropriately logs failures without interrupting the collection process for other domains.

@JimSycurity JimSycurity changed the title feat: AdminSDHolder updates feat: AdminSDHolder updates - BED-6221 Jul 30, 2025
@JimSycurity JimSycurity merged commit 034cb0e into 2.X Aug 4, 2025
2 checks passed
@JimSycurity JimSycurity deleted the jsykora/BED-6178 branch August 4, 2025 13:41
@github-actions github-actions bot locked and limited conversation to collaborators Aug 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request external This pull request is from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants