137 lines
5.4 KiB
Ruby
137 lines
5.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Metasploit
|
|
module Framework
|
|
module LDAP
|
|
|
|
module Client
|
|
def ldap_connect_opts(rhost, rport, connect_timeout, ssl: true, opts: {})
|
|
connect_opts = {
|
|
host: rhost,
|
|
port: rport,
|
|
connect_timeout: connect_timeout,
|
|
proxies: opts[:proxies]
|
|
}
|
|
|
|
if ssl
|
|
connect_opts[:encryption] = {
|
|
method: :simple_tls,
|
|
tls_options: {
|
|
verify_mode: OpenSSL::SSL::VERIFY_NONE
|
|
}
|
|
}
|
|
end
|
|
|
|
case opts[:ldap_auth]
|
|
when Msf::Exploit::Remote::AuthOption::SCHANNEL
|
|
pfx_path = opts[:ldap_cert_file]
|
|
raise Msf::ValidationError, 'The LDAP::CertFile option is required when using SCHANNEL authentication.' if pfx_path.blank?
|
|
raise Msf::ValidationError, 'The SSL option must be enabled when using SCHANNEL authentication.' if ssl != true
|
|
|
|
unless ::File.file?(pfx_path) && ::File.readable?(pfx_path)
|
|
raise Msf::ValidationError, 'Failed to load the PFX certificate file. The path was not a readable file.'
|
|
end
|
|
|
|
begin
|
|
pkcs = OpenSSL::PKCS12.new(File.binread(pfx_path), '')
|
|
rescue StandardError => e
|
|
raise Msf::ValidationError, "Failed to load the PFX file (#{e})"
|
|
end
|
|
|
|
connect_opts[:auth] = {
|
|
method: :sasl,
|
|
mechanism: 'EXTERNAL',
|
|
initial_credential: '',
|
|
challenge_response: true
|
|
}
|
|
connect_opts[:encryption] = {
|
|
method: :start_tls,
|
|
tls_options: {
|
|
verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
|
cert: pkcs.certificate,
|
|
key: pkcs.key
|
|
}
|
|
}
|
|
when Msf::Exploit::Remote::AuthOption::KERBEROS
|
|
raise Msf::ValidationError, 'The Ldap::Rhostname option is required when using Kerberos authentication.' if opts[:ldap_rhostname].blank?
|
|
raise Msf::ValidationError, 'The DOMAIN option is required when using Kerberos authentication.' if opts[:domain].blank?
|
|
|
|
offered_etypes = Msf::Exploit::Remote::AuthOption.as_default_offered_etypes(opts[:ldap_krb_offered_enc_types])
|
|
raise Msf::ValidationError, 'At least one encryption type is required when using Kerberos authentication.' if offered_etypes.empty?
|
|
|
|
kerberos_authenticator = Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::LDAP.new(
|
|
host: opts[:domain_controller_rhost].blank? ? nil : opts[:domain_controller_rhost],
|
|
hostname: opts[:ldap_rhostname],
|
|
realm: opts[:domain],
|
|
username: opts[:username],
|
|
password: opts[:password],
|
|
framework: opts[:framework],
|
|
framework_module: opts[:framework_module],
|
|
cache_file: opts[:ldap_krb5_cname].blank? ? nil : opts[:ldap_krb5_cname],
|
|
ticket_storage: opts[:kerberos_ticket_storage],
|
|
offered_etypes: offered_etypes
|
|
)
|
|
|
|
connect_opts[:auth] = {
|
|
method: :sasl,
|
|
mechanism: 'GSS-SPNEGO',
|
|
initial_credential: proc do
|
|
kerberos_result = kerberos_authenticator.authenticate
|
|
kerberos_result[:security_blob]
|
|
end,
|
|
challenge_response: true
|
|
}
|
|
when Msf::Exploit::Remote::AuthOption::NTLM
|
|
ntlm_client = RubySMB::NTLM::Client.new(
|
|
opts[:username],
|
|
opts[:password],
|
|
workstation: 'WORKSTATION',
|
|
domain: opts[:domain].blank? ? '.' : opts[:domain],
|
|
flags:
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:UNICODE] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:REQUEST_TARGET] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:NTLM] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:ALWAYS_SIGN] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:KEY_EXCHANGE] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:TARGET_INFO] |
|
|
RubySMB::NTLM::NEGOTIATE_FLAGS[:VERSION_INFO]
|
|
)
|
|
|
|
negotiate = proc do |challenge|
|
|
ntlmssp_offset = challenge.index('NTLMSSP')
|
|
type2_blob = challenge.slice(ntlmssp_offset..-1)
|
|
challenge = [type2_blob].pack('m')
|
|
type3_message = ntlm_client.init_context(challenge)
|
|
type3_message.serialize
|
|
end
|
|
|
|
connect_opts[:auth] = {
|
|
method: :sasl,
|
|
mechanism: 'GSS-SPNEGO',
|
|
initial_credential: ntlm_client.init_context.serialize,
|
|
challenge_response: negotiate
|
|
}
|
|
when Msf::Exploit::Remote::AuthOption::PLAINTEXT
|
|
connect_opts[:auth] = {
|
|
method: :simple,
|
|
username: opts[:username],
|
|
password: opts[:password]
|
|
}
|
|
when Msf::Exploit::Remote::AuthOption::AUTO
|
|
unless opts[:username].blank? # plaintext if specified
|
|
connect_opts[:auth] = {
|
|
method: :simple,
|
|
username: opts[:username],
|
|
password: opts[:password]
|
|
}
|
|
end
|
|
end
|
|
|
|
connect_opts
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|