Reuse the ldap connection once established
This commit is contained in:
parent
4a51e028d8
commit
3cbf46c5b7
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue