rapid7 / metasploit-framework

Metasploit Framework
https://www.metasploit.com/
Other
32.92k stars 13.71k forks source link

LDAPS Channel Binding for NTLM and Kerberos #19132

Closed zeroSteiner closed 3 days ago

zeroSteiner commented 3 weeks ago

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 as rex_ntlm and rex_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

References

The following are various resources that were valuable references while implementing these changes.

Neustradamus commented 3 weeks ago

To follow!

adfoster-r7 commented 3 weeks ago

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

Samba doesn't implement LDAP Channel binding as required by the 2020 LDAP channel binding and LDAP signing requirements for Windows. Instead, in 2016 with CVE-2016-2112 we recognised the with no cryptographic connection between the NTLM response or Kerberos token and the TLS layer, that a relay attack was possible.

Samba has chosen to simply deny such sessions by default.

zeroSteiner commented 1 week ago

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.

zeroSteiner commented 1 week ago

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 ``` run LDAP::Auth=plaintext LDAP::Signing=disabled RPORT=389 SSL=false run LDAP::Auth=plaintext LDAP::Signing=disabled RPORT=636 SSL=true run LDAP::Auth=plaintext LDAP::Signing=auto RPORT=389 SSL=false run LDAP::Auth=plaintext LDAP::Signing=auto RPORT=636 SSL=true run LDAP::Auth=plaintext LDAP::Signing=required RPORT=389 SSL=false run LDAP::Auth=plaintext LDAP::Signing=required RPORT=636 SSL=true run LDAP::Auth=kerberos LDAP::Signing=disabled RPORT=389 SSL=false run LDAP::Auth=kerberos LDAP::Signing=disabled RPORT=636 SSL=true run LDAP::Auth=kerberos LDAP::Signing=auto RPORT=389 SSL=false run LDAP::Auth=kerberos LDAP::Signing=auto RPORT=636 SSL=true run LDAP::Auth=kerberos LDAP::Signing=required RPORT=389 SSL=false run LDAP::Auth=kerberos LDAP::Signing=required RPORT=636 SSL=true run LDAP::Auth=ntlm LDAP::Signing=disabled RPORT=389 SSL=false run LDAP::Auth=ntlm LDAP::Signing=disabled RPORT=636 SSL=true run LDAP::Auth=ntlm LDAP::Signing=auto RPORT=389 SSL=false run LDAP::Auth=ntlm LDAP::Signing=auto RPORT=636 SSL=true run LDAP::Auth=ntlm LDAP::Signing=required RPORT=389 SSL=false run LDAP::Auth=ntlm LDAP::Signing=required RPORT=636 SSL=true ```
jheysel-r7 commented 3 days ago

Release Notes

Add 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