From c82e16d34b4d19919c1fcfa6209ed00f14a47d6b Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Wed, 26 Nov 2025 16:13:51 -0500 Subject: [PATCH] Allow toggling the SACL in queries --- lib/msf/core/exploit/remote/ldap/queries.rb | 4 ++-- modules/auxiliary/gather/ldap_query.rb | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/exploit/remote/ldap/queries.rb b/lib/msf/core/exploit/remote/ldap/queries.rb index 5bbdb4948409e..144684191146d 100755 --- a/lib/msf/core/exploit/remote/ldap/queries.rb +++ b/lib/msf/core/exploit/remote/ldap/queries.rb @@ -81,7 +81,7 @@ def perform_ldap_query(ldap, filter, attributes, base, schema_dn, scope: nil) results end - def perform_ldap_query_streaming(ldap, filter, attributes, base, schema_dn, scope: nil) + def perform_ldap_query_streaming(ldap, filter, attributes, base, schema_dn, scope: nil, controls: []) if attributes.nil? || schema_dn.nil? attribute_properties = {} else @@ -96,7 +96,7 @@ def perform_ldap_query_streaming(ldap, filter, attributes, base, schema_dn, scop scope ||= Net::LDAP::SearchScope_WholeSubtree result_count = 0 - ldap.search(base: base, filter: filter, attributes: attributes, scope: scope, return_result: false) do |result| + ldap.search(base: base, filter: filter, attributes: attributes, scope: scope, controls: controls, return_result: false) do |result| result_count += 1 yield result, attribute_properties if block_given? end diff --git a/modules/auxiliary/gather/ldap_query.rb b/modules/auxiliary/gather/ldap_query.rb index 69d005e389a5d..00976440abe5b 100644 --- a/modules/auxiliary/gather/ldap_query.rb +++ b/modules/auxiliary/gather/ldap_query.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::Exploit::Remote::LDAP::ActiveDirectory include Msf::Exploit::Remote::LDAP::Queries include Msf::OptionalSession::LDAP require 'json' @@ -66,6 +67,10 @@ def initialize(info = {}) OptString.new('QUERY_FILTER', [false, 'Filter to send to the target LDAP server to perform the query'], conditions: %w[ACTION == RUN_SINGLE_QUERY]), OptString.new('QUERY_ATTRIBUTES', [false, 'Comma separated list of attributes to retrieve from the server'], conditions: %w[ACTION == RUN_SINGLE_QUERY]) ]) + + register_advanced_options([ + OptBool.new('LDAP::QuerySacl', [true, 'Query the SACL field from security descriptors (requires privileges)', true]) + ]) end def initialize_actions @@ -185,7 +190,13 @@ def run fail_with(Failure::BadConfig, "Could not compile the filter #{filter_string}. Error was #{e}") end - result_count = perform_ldap_query_streaming(ldap, filter, attributes, query_base, schema_dn) do |result, attribute_properties| + controls = [] + unless datastore['LDAP::QuerySacl'] + # omit the control entirely if querying the SACL because that's the default behavior + controls = [adds_build_ldap_sd_control(sacl: false)] + end + + result_count = perform_ldap_query_streaming(ldap, filter, attributes, query_base, schema_dn, controls: controls) do |result, attribute_properties| show_output(normalize_entry(result, attribute_properties), datastore['OUTPUT_FORMAT']) end