Skip to content

Conversation

@zeroSteiner
Copy link
Contributor

The SACL field within security descriptors typically requires elevated privileges to be read. This means that by default if a user queries a security descriptor and does not have the privileges to read the SACL, the entire field is omitted. Microsoft provides a control that can be applied to the query to toggle this, allowing the rest of the security descriptor to be returned where otherwise it'd be omitted. This PR exposes Metasploit's existing control construction as a datastore option so that users may turn this on and off at while. This means that underpriviliged users can not query for security descriptors and get the majority of the data in the field.

Verification

List the steps needed to make sure this thing works

  • Put this updated/hacked version of the ENUM_ACCOUNTS query into the local query file at ~/.msf4/ldap_queries.yaml, it includes the nTSecurityDescriptor field.
  • Start msfconsole and load the ldap_query module
  • Run the HACKED_ENUM_ACCOUNTS action with a normal user account and LDAP::QuerySacl=false, see the security descriptor field is present
  • Toggle LDAP::QuerySacl back to true and run it again, see no security descriptor field (this is the old behavior where the SACL is included by default)
---
queries:
  - action: HACKED_ENUM_ACCOUNTS
    description: 'Dump info about all known user accounts in the domain.'
    filter: '(|(objectClass=organizationalPerson)(sAMAccountType=805306368)(objectcategory=user)(objectClass=user))'
    attributes:
      - dn
      - name
      - nTSecurityDescriptor
      - description
      - displayName
      - sAMAccountName
      - objectSID
      - userPrincipalName
      - userAccountControl
      - homeDirectory
      - homeDrive
      - profilePath
      - memberof
      - lastLogoff
      - lastLogon
      - lastLogonDate
      - logonCount
      - badPwdCount
      - pwdLastSet
      - SmartcardLogonRequired
      - LastBadPasswordAttempt
      - PasswordLastSet
      - PaswordNeverExpires
    references:
      - http://www.ldapexplorer.com/en/manual/109050000-famous-filters.htm
      - https://adsecurity.org/wp-content/uploads/2016/08/DEFCON24-2016-Metcalf-BeyondTheMCSE-RedTeamingActiveDirectory.pdf

@zeroSteiner zeroSteiner marked this pull request as ready for review November 26, 2025 21:31
])

register_advanced_options([
OptBool.new('LDAP::QuerySacl', [true, 'Query the SACL field from security descriptors (requires privileges)', true])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would be in favor of turning this off by default but:

  1. I'd be concerned that non-Active Directory LDAP implementations might start failing queries if they don't support the control
  2. It'd technically change the old behavior

It could in thoery be made automatic where we'd fingerprint if the target LDAP server is AD and toggle it to false if so, or toggle it to false and re-issue a query if we noticed that we both requested a security descriptor and it was omitted in the results.

Copy link
Contributor

Choose a reason for hiding this comment

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

While other offensive security tooling have their default set to not query for the SACL, I'd leave this one to false. Mostly because it is a general purpose LDAP query module. Leave the finger printing and/or re-issuing queries to operators so that we can avoid any unnecessary traffic from the module that might trip identity products. Some valid options I see is;

1.) Create a wrapper module for "Microsoft LDAP" where you have an interactive prompt to make LDAP queries with a single connection.
2.) If the ntSecurityDescriptor attribute was explicitly provided and no value was returned when there are results, throw a debug or information message stating "Failed to query ntSecurityDescriptor, for non-administrative users please set LDAP::QuerySACL to false".

@zeroSteiner zeroSteiner force-pushed the feat/mod/ldap-query/toggle-sacl branch from 4507a9f to c82e16d Compare November 26, 2025 21:42
@skylerknecht
Copy link
Contributor

skylerknecht commented Nov 26, 2025

Seems to work as expected.

Actions tested;

  1. Copied the two modified files into my installation.
  2. Restarted Metasploit
  3. Set attributes to *,ntSecurityDescriptor
  4. Set filter to (objectClass=user)
  5. Set LDAP::QuerySacl set to false
  6. Set action RUN_SINGLE_QUERY
  7. Successfully gathered SDDL not containing the SACL as a non-administrative user as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants