Reuse the ldap connection once established

This commit is contained in:
Spencer McIntyre 2024-02-21 16:24:13 -05:00
parent 4a51e028d8
commit 3cbf46c5b7
1 changed files with 59 additions and 70 deletions

View File

@ -97,72 +97,42 @@ class MetasploitModule < Msf::Auxiliary
end end
def query_ldap_server(raw_filter, attributes, base_prefix: nil) def query_ldap_server(raw_filter, attributes, base_prefix: nil)
ldap_connect do |ldap| if base_prefix.blank?
validate_bind_success!(ldap) full_base_dn = @base_dn.to_s
else
if !@base_dn.blank? full_base_dn = "#{base_prefix},#{@base_dn}"
vprint_status("Using already discovered base DN: #{@base_dn}")
elsif (@base_dn = datastore['BASE_DN'])
print_status("User-specified base DN: #{@base_dn}")
else
print_status('Discovering base DN automatically')
unless (@base_dn = discover_base_dn(ldap))
print_warning("Couldn't discover base DN!")
end
end
if @base_dn.blank?
fail_with(Failure::BadConfig, 'No base DN was found or specified, cannot continue!')
end
if base_prefix.blank?
full_base_dn = @base_dn.to_s
else
full_base_dn = "#{base_prefix},#{@base_dn}"
end
begin
filter = Net::LDAP::Filter.construct(raw_filter)
rescue StandardError => e
fail_with(Failure::BadConfig, "Could not compile the filter! Error was #{e}")
end
# Set the value of LDAP_SERVER_SD_FLAGS_OID flag so everything but
# the SACL flag is set, as we need administrative privileges to retrieve
# the SACL from the ntSecurityDescriptor attribute on Windows AD LDAP servers.
#
# Note that without specifying the LDAP_SERVER_SD_FLAGS_OID control in this manner,
# the LDAP searchRequest will default to trying to grab all possible attributes of
# the ntSecurityDescriptor attribute, hence resulting in an attempt to retrieve the
# SACL even if the user is not an administrative user.
#
# Now one may think that we would just get the rest of the data without the SACL field,
# however in reality LDAP will cause that attribute to just be blanked out if a part of it
# cannot be retrieved, so we just will get nothing for the ntSecurityDescriptor attribute
# in these cases if the user doesn't have permissions to read the SACL.
all_but_sacl_flag = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
control_values = [all_but_sacl_flag].map(&:to_ber).to_ber_sequence.to_s.to_ber
controls = []
controls << [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence
returned_entries = ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)
query_result_table = ldap.get_operation_result.table
validate_query_result!(query_result_table, filter)
if returned_entries.blank?
vprint_error("No results found for #{filter}.")
nil
else
returned_entries
end
end end
rescue Rex::ConnectionTimeout begin
fail_with(Failure::Unreachable, "Couldn't reach #{datastore['RHOST']}!") filter = Net::LDAP::Filter.construct(raw_filter)
rescue Net::LDAP::Error => e rescue StandardError => e
fail_with(Failure::UnexpectedReply, "Could not query #{datastore['RHOST']}! Error was: #{e.message}") fail_with(Failure::BadConfig, "Could not compile the filter! Error was #{e}")
end
# Set the value of LDAP_SERVER_SD_FLAGS_OID flag so everything but
# the SACL flag is set, as we need administrative privileges to retrieve
# the SACL from the ntSecurityDescriptor attribute on Windows AD LDAP servers.
#
# Note that without specifying the LDAP_SERVER_SD_FLAGS_OID control in this manner,
# the LDAP searchRequest will default to trying to grab all possible attributes of
# the ntSecurityDescriptor attribute, hence resulting in an attempt to retrieve the
# SACL even if the user is not an administrative user.
#
# Now one may think that we would just get the rest of the data without the SACL field,
# however in reality LDAP will cause that attribute to just be blanked out if a part of it
# cannot be retrieved, so we just will get nothing for the ntSecurityDescriptor attribute
# in these cases if the user doesn't have permissions to read the SACL.
all_but_sacl_flag = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
control_values = [all_but_sacl_flag].map(&:to_ber).to_ber_sequence.to_s.to_ber
controls = []
controls << [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence
returned_entries = @ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)
query_result_table = @ldap.get_operation_result.table
validate_query_result!(query_result_table, filter)
return nil if returned_entries.empty?
returned_entries
end end
def query_ldap_server_certificates(esc_raw_filter, esc_name) def query_ldap_server_certificates(esc_raw_filter, esc_name)
@ -372,11 +342,30 @@ class MetasploitModule < Msf::Auxiliary
@base_dn = nil @base_dn = nil
@vuln_certificate_details = {} # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details. @vuln_certificate_details = {} # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details.
find_esc1_vuln_cert_templates ldap_connect do |ldap|
find_esc2_vuln_cert_templates validate_bind_success!(ldap)
find_esc3_vuln_cert_templates
find_enrollable_vuln_certificate_templates if (@base_dn = datastore['BASE_DN'])
print_vulnerable_cert_info print_status("User-specified base DN: #{@base_dn}")
else
print_status('Discovering base DN automatically')
unless (@base_dn = discover_base_dn(ldap))
fail_with(Failure::NotFound, "Couldn't discover base DN!")
end
end
@ldap = ldap
find_esc1_vuln_cert_templates
find_esc2_vuln_cert_templates
find_esc3_vuln_cert_templates
find_enrollable_vuln_certificate_templates
print_vulnerable_cert_info
end
rescue Rex::ConnectionError => e
print_error("#{e.class}: #{e.message}")
rescue Net::LDAP::Error => e
print_error("#{e.class}: #{e.message}")
end end
end end