Switch to an enum option for the signing

This commit is contained in:
Spencer McIntyre 2024-05-02 16:25:10 -04:00
parent 6d915dbb55
commit 69d603e6fc
11 changed files with 119 additions and 115 deletions

View File

@ -196,7 +196,6 @@ Module options (auxiliary/gather/ldap_esc_vulnerable_cert_finder):
DOMAIN no The domain to authenticate to
PASSWORD no The password to authenticate with
REPORT_NONENROLLABLE false yes Report nonenrollable certificate templates
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS yes The target host(s), see https://github.com/rapid7/metasploit
-framework/wiki/Using-Metasploit
RPORT 389 yes The target port

View File

@ -107,16 +107,15 @@ msf6 auxiliary(admin/ldap/shadow_credentials) > show options
Module options (auxiliary/admin/ldap/shadow_credentials):
Name Current Setting Required Description
---- --------------- -------- -----------
DOMAIN no The domain to authenticate to
PASSWORD no The password to authenticate with
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
TARGET_USER yes The target to write to
USERNAME no The username to authenticate with
Name Current Setting Required Description
---- --------------- -------- -----------
DOMAIN no The domain to authenticate to
PASSWORD no The password to authenticate with
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
TARGET_USER yes The target to write to
USERNAME no The username to authenticate with
When ACTION is REMOVE:
@ -262,4 +261,4 @@ msf6 auxiliary(admin/ldap/shadow_credentials) > run rhost=20.92.148.129 username
[*] Certificate stored at: /home/user/.msf4/loot/20240404122240_default_20.92.148.129_windows.ad.cs_785877.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 1107833b-0eb6-0477-a7c6-3590b326851a
[*] Auxiliary module execution completed
```
```

View File

@ -60,18 +60,17 @@ msf5 auxiliary(admin/ldap/vmware_vcenter_vmdir_auth_bypass) > options
Module options (auxiliary/admin/ldap/vmware_vcenter_vmdir_auth_bypass):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
NEW_PASSWORD no Password of admin user to add
NEW_USERNAME no Username of admin user to add
PASSWORD no The password to authenticate with
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 636 yes The target port
SSL true no Enable SSL on the LDAP connection
USERNAME no The username to authenticate with
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
NEW_PASSWORD no Password of admin user to add
NEW_USERNAME no Username of admin user to add
PASSWORD no The password to authenticate with
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 636 yes The target port
SSL true no Enable SSL on the LDAP connection
USERNAME no The username to authenticate with
Auxiliary action:

View File

@ -116,7 +116,6 @@ Module options (auxiliary/gather/ldap_esc_vulnerable_cert_finder):
BIND_DN DAFOREST\Administrator no The username to authenticate to LDAP server
BIND_PW theAdmin123 no Password for the BIND_DN
REPORT_NONENROLLABLE false yes Report nonenrollable certificate templates
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS 172.26.104.157 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection

View File

@ -28,27 +28,25 @@ msf5 auxiliary(gather/ldap_hashdump) > options
Module options (auxiliary/gather/ldap_hashdump):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
MAX_LOOT no Maximum number of LDAP entries to loot
PASSWORD no The password to authenticate with
PASS_ATTR userPassword, sambantpassword, sambalmpassword, mailu yes LDAP attribute, that contains password hashes
serpassword, password, pwdhistory, passwordhistory, c
learpassword
READ_TIMEOUT 600 no LDAP read timeout in seconds
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS 127.0.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.ht
ml
RPORT 1389 yes The target port
SSL true no Enable SSL on the LDAP connection
THREADS 1 yes The number of concurrent threads (max one per host)
USERNAME no The username to authenticate with
USER_ATTR dn no LDAP attribute(s), that contains username
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it]
DOMAIN no The domain to authenticate to
MAX_LOOT no Maximum number of LDAP entries to loot
PASSWORD no The password to authenticate with
PASS_ATTR userPassword, sambantpassword, sambalmpassword, mailu yes LDAP attribute, that contains password hashes
serpassword, password, pwdhistory, passwordhistory, c
learpassword
READ_TIMEOUT 600 no LDAP read timeout in seconds
RHOSTS 127.0.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.h
tml
RPORT 1389 yes The target port
SSL true no Enable SSL on the LDAP connection
THREADS 1 yes The number of concurrent threads (max one per host)
USERNAME no The username to authenticate with
USER_ATTR dn no LDAP attribute(s), that contains username
Auxiliary action:
Name Description
---- -----------
Dump Dump all LDAP data

View File

@ -215,16 +215,15 @@ msf6 auxiliary(gather/ldap_query) > show options
Module options (auxiliary/gather/ldap_query):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
PASSWORD thePassword123 no The password to authenticate with
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS 172.27.51.83 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
USERNAME normal@daforest.com no The username to authenticate with
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
PASSWORD thePassword123 no The password to authenticate with
RHOSTS 172.27.51.83 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
USERNAME normal@daforest.com no The username to authenticate with
When ACTION is RUN_QUERY_FILE:
@ -242,7 +241,6 @@ Module options (auxiliary/gather/ldap_query):
QUERY_FILTER no Filter to send to the target LDAP server to perform the query
Auxiliary action:
Name Description
---- -----------
RUN_QUERY_FILE Execute a custom set of LDAP queries from the JSON or YAML file specified by QUERY_FILE.

View File

@ -39,18 +39,16 @@ If you already have the LDAP base DN, you may set it in this option.
msf5 > use auxiliary/gather/vmware_vcenter_vmdir_ldap
msf5 auxiliary(gather/vmware_vcenter_vmdir_ldap) > options
Module options (auxiliary/gather/vmware_vcenter_vmdir_ldap):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
PASSWORD no The password to authenticate with
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 636 yes The target port
SSL true no Enable SSL on the LDAP connection
USERNAME no The username to authenticate with
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
DOMAIN no The domain to authenticate to
PASSWORD no The password to authenticate with
REQUIRE_SIGNING true yes Use signed and encrypted LDAP
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 636 yes The target port
SSL true no Enable SSL on the LDAP connection
USERNAME no The username to authenticate with
Auxiliary action:

View File

@ -127,18 +127,16 @@ module Metasploit
case opts[:ldap_auth]
when Msf::Exploit::Remote::AuthOption::SCHANNEL
raise Msf::ValidationError, 'The SSL option must be enabled when using SCHANNEL authentication.' unless ssl
connect_opts.merge!(ldap_auth_opts_schannel(opts))
connect_opts.merge!(ldap_auth_opts_schannel(opts, ssl))
when Msf::Exploit::Remote::AuthOption::KERBEROS
connect_opts.merge!(ldap_auth_opts_kerberos(opts))
connect_opts.merge!(ldap_auth_opts_kerberos(opts, ssl))
when Msf::Exploit::Remote::AuthOption::NTLM
connect_opts.merge!(ldap_auth_opts_ntlm(opts))
connect_opts.merge!(ldap_auth_opts_ntlm(opts, ssl))
when Msf::Exploit::Remote::AuthOption::PLAINTEXT
connect_opts.merge!(ldap_auth_opts_plaintext(opts))
when Msf::Exploit::Remote::AuthOption::AUTO
if opts[:username].present? && opts[:domain].present?
connect_opts.merge!(ldap_auth_opts_ntlm(opts))
connect_opts.merge!(ldap_auth_opts_ntlm(opts, ssl))
elsif opts[:username].present?
connect_opts.merge!(ldap_auth_opts_plaintext(opts))
end
@ -149,15 +147,15 @@ module Metasploit
private
def ldap_auth_opts_kerberos(opts)
def ldap_auth_opts_kerberos(opts, ssl)
auth_opts = {}
raise Msf::ValidationError, 'The Ldap::Rhostname option is required when using Kerberos authentication.' if opts[:ldap_rhostname].blank?
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?
use_gss_checksum = opts[:should_encrypt]
sign_and_seal = opts.fetch(:sign_and_seal, !ssl)
kerberos_authenticator = Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::LDAP.new(
host: opts[:domain_controller_rhost].blank? ? nil : opts[:domain_controller_rhost],
hostname: opts[:ldap_rhostname],
@ -170,7 +168,7 @@ module Metasploit
ticket_storage: opts[:kerberos_ticket_storage],
offered_etypes: offered_etypes,
mutual_auth: true,
use_gss_checksum: use_gss_checksum
use_gss_checksum: sign_and_seal
)
encryptor = SpnegoKerberosEncryptor.new(kerberos_authenticator)
@ -184,14 +182,14 @@ module Metasploit
challenge_response: true
}
if opts[:should_encrypt]
if sign_and_seal
auth_opts[:auth][:auth_context_setup] = encryptor.method(:kerberos_setup)
end
auth_opts
end
def ldap_auth_opts_ntlm(opts)
def ldap_auth_opts_ntlm(opts, ssl)
auth_opts = {}
flags = RubySMB::NTLM::NEGOTIATE_FLAGS[:UNICODE] |
RubySMB::NTLM::NEGOTIATE_FLAGS[:REQUEST_TARGET] |
@ -202,7 +200,8 @@ module Metasploit
RubySMB::NTLM::NEGOTIATE_FLAGS[:TARGET_INFO] |
RubySMB::NTLM::NEGOTIATE_FLAGS[:VERSION_INFO]
if opts[:should_encrypt]
sign_and_seal = opts.fetch(:sign_and_seal, !ssl)
if sign_and_seal
flags = flags |
RubySMB::NTLM::NEGOTIATE_FLAGS[:SIGN] |
RubySMB::NTLM::NEGOTIATE_FLAGS[:SEAL] |
@ -234,7 +233,7 @@ module Metasploit
challenge_response: negotiate
}
if opts[:should_encrypt]
if sign_and_seal
auth_opts[:auth][:auth_context_setup] = encryptor.method(:ntlm_setup)
end
@ -243,6 +242,8 @@ module Metasploit
def ldap_auth_opts_plaintext(opts)
auth_opts = {}
raise Msf::ValidationError, 'Can not sign and seal when using Plaintext authentication.' if opts.fetch(:sign_and_seal, false)
auth_opts[:auth] = {
method: :simple,
username: opts[:username],
@ -251,10 +252,12 @@ module Metasploit
auth_opts
end
def ldap_auth_opts_schannel(opts)
def ldap_auth_opts_schannel(opts, ssl)
auth_opts = {}
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.' unless ssl
raise Msf::ValidationError, 'The LDAP::CertFile option is required when using Schannel authentication.' if pfx_path.blank?
raise Msf::ValidationError, 'Can not sign and seal when using Schannel authentication.' if opts.fetch(:sign_and_seal, false)
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.'

View File

@ -32,8 +32,7 @@ module Msf
OptBool.new('SSL', [false, 'Enable SSL on the LDAP connection', false]),
Msf::OptString.new('DOMAIN', [false, 'The domain to authenticate to']),
Msf::OptString.new('USERNAME', [false, 'The username to authenticate with'], aliases: ['BIND_DN']),
Msf::OptString.new('PASSWORD', [false, 'The password to authenticate with'], aliases: ['BIND_PW']),
OptBool.new('REQUIRE_SIGNING', [true, 'Use signed and encrypted LDAP', true])
Msf::OptString.new('PASSWORD', [false, 'The password to authenticate with'], aliases: ['BIND_PW'])
])
register_advanced_options(
@ -42,7 +41,8 @@ module Msf
*kerberos_storage_options(protocol: 'LDAP'),
*kerberos_auth_options(protocol: 'LDAP', auth_methods: Msf::Exploit::Remote::AuthOption::LDAP_OPTIONS),
Msf::OptPath.new('LDAP::CertFile', [false, 'The path to the PKCS12 (.pfx) certificate file to authenticate with'], conditions: ['LDAP::Auth', '==', Msf::Exploit::Remote::AuthOption::SCHANNEL]),
OptFloat.new('LDAP::ConnectTimeout', [true, 'Timeout for LDAP connect', 10.0])
OptFloat.new('LDAP::ConnectTimeout', [true, 'Timeout for LDAP connect', 10.0]),
OptEnum.new('LDAP::Signing', [true, 'Use signed and sealed (encrypted) LDAP', 'auto', %w[ disabled auto required ]])
]
)
end
@ -80,26 +80,37 @@ module Msf
password: datastore['PASSWORD'],
domain: datastore['DOMAIN'],
domain_controller_rhost: datastore['DomainControllerRhost'],
should_encrypt: datastore['REQUIRE_SIGNING'],
ldap_auth: datastore['LDAP::Auth'],
ldap_cert_file: datastore['LDAP::CertFile'],
ldap_rhostname: datastore['Ldap::Rhostname'],
ldap_krb_offered_enc_types: datastore['Ldap::KrbOfferedEncryptionTypes'],
ldap_krb5_cname: datastore['Ldap::Krb5Ccname'],
ldap_rhostname: datastore['LDAP::Rhostname'],
ldap_krb_offered_enc_types: datastore['LDAP::KrbOfferedEncryptionTypes'],
ldap_krb5_cname: datastore['LDAP::Krb5Ccname'],
proxies: datastore['Proxies'],
framework_module: self
}
case datastore['LDAP::Signing']
when 'required'
opts[:sign_and_seal] = true
when 'disabled'
opts[:sign_and_seal] = false
end
result = ldap_connect_opts(rhost, rport, datastore['LDAP::ConnectTimeout'], ssl: datastore['SSL'], opts: opts)
begin
result = ldap_connect_opts(rhost, rport, datastore['LDAP::ConnectTimeout'], ssl: datastore['SSL'], opts: opts)
rescue Msf::ValidationError => e
fail_with(Msf::Module::Failure::BadConfig, e.message)
end
# Now that the options have been resolved (including auto possibly resolving to NTLM), check whether this is a valid config
if result[:auth] &&
result[:auth][:method] == :sasl &&
result[:auth][:mechanism] == 'GSS-SPNEGO' &&
datastore['SSL'] &&
datastore['REQUIRE_SIGNING']
# Domain Controllers don't seem to support signing and connection over SSL. Gotta pick one or the other.
fail_with(Msf::Module::Failure::BadConfig, 'SSL not supported with signing. Set either SSL or REQUIRE_SIGNING, but not both.')
if result[:auth] && datastore['LDAP::Signing'] == 'required'
unless (result[:auth][:method] == :sasl && result[:auth][:mechanism] == 'GSS-SPNEGO')
fail_with(Msf::Module::Failure::BadConfig, 'The authentication configuration does not support signing. Change either LDAP::Auth or LDAP::Signing.')
end
if result[:encryption]
# Domain Controllers don't seem to support signing and connection over SSL. Gotta pick one or the other.
fail_with(Msf::Module::Failure::BadConfig, 'SSL not supported with signing. Change either SSL or LDAP::Signing.')
end
end
result
@ -257,7 +268,7 @@ module Msf
fail_with(Msf::Module::Failure::NoTarget, 'Target does not support the simple authentication mechanism!')
when 8
signing_statement = ''
signing_statement = 'May require LDAP signing to be enabled (`set REQUIRE_SIGNING true`). ' unless datastore['REQUIRE_SIGNING']
signing_statement = 'May require LDAP signing to be enabled (`set LDAP::EnableSigning true`). ' unless datastore['LDAP::EnableSigning']
fail_with(Msf::Module::Failure::NoTarget, "Server requires a stronger form of authentication! #{signing_statement}The error was: #{bind_result[:error_message].strip}")
when 14

View File

@ -1,4 +1,4 @@
module Rex::Proto::LDAP
class LdapException < RuntimeError
end
end
class LdapException < RuntimeError
end
end

View File

@ -1,18 +1,18 @@
module Rex::Proto::Sasl
# Wrap the data in a SASL structure, per RFC 4422 (basically just prepends a big-endian encoded 32-bit integer representing the length)
def wrap_sasl(data)
length = [data.length].pack('N')
# Wrap the data in a SASL structure, per RFC 4422 (basically just prepends a big-endian encoded 32-bit integer representing the length)
def wrap_sasl(data)
length = [data.length].pack('N')
length + data
end
# Unwraps the data from a SASL structure, per RFC 4422
def unwrap_sasl(data)
length = data[0,4].unpack('N')[0]
if length != data.length + 4
raise ArgumentError.new('Invalid SASL structure')
end
length + data
end
data[4,length]
# Unwraps the data from a SASL structure, per RFC 4422
def unwrap_sasl(data)
length = data[0,4].unpack('N')[0]
if length != data.length + 4
raise ArgumentError.new('Invalid SASL structure')
end
end
data[4,length]
end
end