-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LDAPS Channel Binding for NTLM and Kerberos #19132
LDAPS Channel Binding for NTLM and Kerberos #19132
Conversation
To follow! |
It's a shame we can't add this to our automated ldap/samba tests - https://wiki.samba.org/index.php/Configuring_LDAP_over_SSL_(LDAPS)_on_a_Samba_AD_DC
|
Marked this as blocked because I think we'll want to land #19127 which will create conflicts. At that point, I'll rebase this work on top of those changes. |
This updates the #build_gss_ap_req_checksum_value method to allow control over the flags and channel binding information.
a889a8b
to
2bf402f
Compare
I ran through all the combinations I could think of using this resource script against a DC which required signing and channel binding. Everything I expected to work did work. Cases that failed were expected to fail for the following reasons:
ldap_test.rc
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work 👍 After a thorough review I think this is good to land. Testing was as expected:
Testing on current upstream-master
With LdapEnforceChannelBinding = 2, the module fails to connect when valid credentials are provided: Invalid credentials provided!
msf6 auxiliary(gather/ldap_query) > run rport=636 ssl=true rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=LABS1COLLABU0 action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[-] Auxiliary aborted due to failure: no-access: Invalid credentials provided!
[*] Auxiliary module execution completed
Testing on this PR (upstream/pr/19132)
With the changes in this PR now the module is able to successfully connect with the same (correct) credentials when LdapEnforceChannelBinding = 2
msf6 auxiliary(gather/ldap_query) > run rport=636 ssl=true rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=LABS1COLLABU0 action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[*] 3.22.14.197:636 Getting root DSE
[+] 3.22.14.197:636 Discovered base DN: DC=labs1collabu0,DC=local
DC=labs1collabu0,DC=local
=========================
Name Attributes
---- ----------
lockoutduration 0:00:10:00
lockoutthreshold 0
maxpwdage 10675199:02:48:05
minpwdage 0:00:00:00
minpwdlength 0
ms-ds-machineaccountquota 10
name labs1collabu0
objectsid S-1-5-21-795503-3050334394-3644400624
[*] Query returned 1 result.
[*] Auxiliary module execution completed
The module still works with LDAP and NTLM authentication:
msf6 auxiliary(gather/ldap_query) > run LDAP::Auth=ntlm RPORT=389 SSL=false rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=LABS1COLLABU0 action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[*] Discovering base DN automatically
[+] 3.22.14.197:389 Discovered base DN: DC=labs1collabu0,DC=local
DC=labs1collabu0,DC=local
=========================
Name Attributes
---- ----------
lockoutduration 0:00:10:00
lockoutthreshold 0
maxpwdage 10675199:02:48:05
minpwdage 0:00:00:00
minpwdlength 0
ms-ds-machineaccountquota 10
name labs1collabu0
objectsid S-1-5-21-795503-3050334394-3644400624
[*] Query returned 1 result.
[*] Auxiliary module execution completed
The module still works with LDAPS and NTLM authentication with channel binding
msf6 auxiliary(gather/ldap_query) > run LDAP::Auth=ntlm RPORT=636 SSL=true rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=LABS1COLLABU0 action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[*] Discovering base DN automatically
[+] 3.22.14.197:636 Discovered base DN: DC=labs1collabu0,DC=local
DC=labs1collabu0,DC=local
=========================
Name Attributes
---- ----------
lockoutduration 0:00:10:00
lockoutthreshold 0
maxpwdage 10675199:02:48:05
minpwdage 0:00:00:00
minpwdlength 0
ms-ds-machineaccountquota 10
name labs1collabu0
objectsid S-1-5-21-795503-3050334394-3644400624
[*] Query returned 1 result.
[*] Auxiliary module execution completed
The module still works with LDAP and Kerberos authentication:
msf6 auxiliary(gather/ldap_query) > run LDAP::Auth=kerberos LDAP::Rhostname=srv-adds01.labs1collabu0.local DomainControllerRhost=3.22.14.197 RPORT=389 SSL=false rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=labs1collabu0.local action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[+] 3.22.14.197:88 - Received a valid TGT-Response
[*] 3.22.14.197:389 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20240510131946_default_3.22.14.197_mit.kerberos.cca_737339.bin
[+] 3.22.14.197:88 - Received a valid TGS-Response
[*] 3.22.14.197:389 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20240510131946_default_3.22.14.197_mit.kerberos.cca_520137.bin
[+] 3.22.14.197:88 - Received a valid delegation TGS-Response
[+] 3.22.14.197:88 - Received AP-REQ. Extracting session key...
[*] Discovering base DN automatically
[+] 3.22.14.197:389 Discovered base DN: DC=labs1collabu0,DC=local
DC=labs1collabu0,DC=local
=========================
Name Attributes
---- ----------
lockoutduration 0:00:10:00
lockoutthreshold 0
maxpwdage 10675199:02:48:05
minpwdage 0:00:00:00
minpwdlength 0
ms-ds-machineaccountquota 10
name labs1collabu0
objectsid S-1-5-21-795503-3050334394-3644400624
[*] Query returned 1 result.
[*] Auxiliary module execution **completed**
The module still works with LDAPS and Kerberos authentication with channel binding
msf6 auxiliary(gather/ldap_query) > run LDAP::Auth=kerberos LDAP::Rhostname=srv-adds01.labs1collabu0.local DomainControllerRhost=3.22.14.197 RPORT=636 SSL=true rhosts=3.22.14.197 username=jheysel password=ChangeM3! domain=labs1collabu0.local action=ENUM_DOMAIN
[*] Running module against 3.22.14.197
[+] 3.22.14.197:88 - Received a valid TGT-Response
[*] 3.22.14.197:636 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20240510132411_default_3.22.14.197_mit.kerberos.cca_670902.bin
[+] 3.22.14.197:88 - Received a valid TGS-Response
[*] 3.22.14.197:636 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20240510132411_default_3.22.14.197_mit.kerberos.cca_809948.bin
[+] 3.22.14.197:88 - Received a valid delegation TGS-Response
[*] Discovering base DN automatically
[+] 3.22.14.197:636 Discovered base DN: DC=labs1collabu0,DC=local
DC=labs1collabu0,DC=local
=========================
Name Attributes
---- ----------
lockoutduration 0:00:10:00
lockoutthreshold 0
maxpwdage 10675199:02:48:05
minpwdage 0:00:00:00
minpwdlength 0
ms-ds-machineaccountquota 10
name labs1collabu0
objectsid S-1-5-21-795503-3050334394-3644400624
[*] Query returned 1 result.
[*] Auxiliary module execution completed
Release NotesAdd channel binding information to Metasploit's NTLM and Kerberos authentication for the LDAP protocol. This enables users to authenticate to domain controllers where the hardened security configuration setting is in place |
Background
In 2020, Microsoft started adding options to harden the conifugraiton of LDAP on AD DS servers (domain controllers). These settings included channel binding and signing requirements. Microsoft posted an article here with additional details.
This pull request adds channel binding information to Metasploit's NTLM and Kerberos authentication for the LDAP protocol. This enables users to authenticate to domain controllers where the hardened security configuration setting is in place (
LdapEnforceChannelBinding
= 2). Prior to these changes, when a user attempted to authenticate to an LDAPS service where channel binding was required, the authentication attempt would fail with an error that the credentials were invalid. This error is of course misleading because the credentials are correct, but authentication failed for other reasons. With these changes in place, the authenticaiton will succeed without any additional changes from the user.Implementation
The channel binding is the MD5 hash of the
gss_channel_bindings_struct
which itself includes a hash of the peer's TLS certificate. The hashing algorithm of the peer's certificiate is "almost always SHA256" but can be different in certain scenarios as described here. The channel binding token is the same for NTLM and for Kerberos, however it's placed in different locations of the negotiation frames. For NTLM it's an additional AV_PAIR structure, while for Kerberos, it's included in the checksum field of the AP-REQ structure.The actual authentication logic was moved into dedicated adapter classes, which register themselves with the
Net::LDAP
library asrex_ntlm
andrex_kerberos
. This cleans up the code a bit, makes it reusable but most importantly is necessary to expose the connections#peer_cert
for the channel bindings.This PR also adds some updates to the error handling for a few of the LDAP modules to avoid stack traces for various connection related errors.
Testing Steps
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters\LdapEnforceChannelBinding
registry setting to 2 for "Always"auxiliary/gather/ldap_query
run LDAP::Auth=ntlm RPORT=389 SSL=false
)run LDAP::Auth=ntlm RPORT=636 SSL=true
)run LDAP::Auth=kerberos RPORT=389 SSL=false
)run LDAP::Auth=kerberos RPORT=636 SSL=true
)References
The following are various resources that were valuable references while implementing these changes.