Repository navigation
Verify the client's mechListMIC on the final SPNEGO leg - #310
Open
Pushpenderrathore wants to merge 2 commits into
Open
Pushpenderrathore wants to merge 2 commits into
Pushpenderrathore wants to merge 2 commits into
Conversation
Provider::Multi::Authenticator#process read only the client's first-listed mechanism when routing a NegTokenInit. That handed routing to the client: reordering a mechTypeList, without removing any mechanism, was enough to steer the server to a weaker sub-provider (NTLM when both sides supported Kerberos). The gap was tracked in rapid7#304. Walk the client's full mechTypeList, pick the server's most-preferred advertised mechanism that the client also offers, and route to that. When the server's choice is not the mechanism the client's optimistic mechToken is for, reply with a NegTokenResp carrying accept-incomplete and supportedMech, per RFC 4178 section 4.2.2, so the client resends a token for the server-selected mechanism. This is server-side routing hardening, not a replacement for a mechListMIC verifier. An on-path attacker who rewrites the mechTypeList before signing is in effect is still able to drop mechanisms the client offered; stopping that requires computing and verifying the mechListMIC, which is tracked separately on the issue.
The last open piece of rapid7#304. Provider::Multi now remembers the DER-encoded mechTypeList the client sent in its first NegTokenInit, and when the client attaches a mechListMIC to its final NegTokenResp the server verifies the HMAC using the negotiated NTLM session key before accepting the auth. The MIC is REQUIRED (per MS-SPNG section 3.2.5.5) on the mismatch path that the preceding change introduced: when the server replied accept-incomplete because its preferred mechanism was not the client's first-listed one. On the single-mechanism path the MIC remains OPTIONAL per RFC 4178 and is only verified when present. Scope: - Only NTLM session keys are used for verification. Kerberos MIC verification needs the service's long-term key, which the Kerberos sub-provider does not hold, so a Kerberos-negotiated session takes the existing on_mech_token path and skips the MIC check. - The server does not emit its own mechListMIC back to the client. Clients that require one from the server are a follow-up. Catches the standard SPNEGO drop attack when the client is spec-compliant: on-path attacker strips Kerberos from the client's mechTypeList, the server sees only NTLM and routes to NTLM, but the client's MIC was computed over its original [Kerberos, NTLM] view. The server's expected MIC over [NTLM] does not match the client's MIC, so authentication fails.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The remaining half of #304. #309 moved the server to pick its own preferred mechanism out of the client's
mechTypeList, which closes the reorder gap, but amechListMICcheck is still needed to catch an on-path attacker who drops a mechanism from the list before the server sees it. This PR adds that verifier.Provider::Multi::Authenticatornow remembers the DER-encodedmechTypeListfrom the firstNegTokenInit. When the client attaches amechListMICto its finalNegTokenRespthe server computes HMAC-MD5 under the NTLM client-to-server signing key derived from the negotiated session key and constant-time compares it to the client's MIC. If the comparison fails, auth returnsSTATUS_LOGON_FAILURE.Per
[MS-SPNG]section 3.2.5.5 the MIC is REQUIRED on the mismatch path #309 introduced (server-chosen mechanism differs from the client's first-listed one). On the single-mechanism / no-mismatch path RFC 4178 keeps the MIC OPTIONAL, so the server only verifies when the client sent one.Depends on #309 - this branch is stacked on it.
Scope
on_mech_tokenhandler path and the MIC check is skipped, because the Kerberos sub-provider does not hold the service key needed to derive a verifier. That is a separate hardening.mechListMICare a follow-up.Lab PoC
Scripted NTLM client + authenticator wired up to five scenarios. The baseline column swaps
lib/ruby_smb/gss/provider/multi.rbto #309's version (no verifier). Everything else identical.C is the real target: a spec-conformant Windows client in a drop-attack scenario produces exactly these bytes, and the verifier catches it.
Verification Steps
bundle exec rspec spec/lib/ruby_smb/gss/provider/multi_spec.rbpasses with the four new MIC testsTest Evidence
New describe block
the client's mechListMIC on the final legwith four cases:accepts a valid MIC on the single-mechanism (no-mismatch) pathrejects a MIC that was computed over a different mechTypeListrejects a MIC with one bit flippedleaves the single-mechanism path alone when no MIC is sent (RFC 4178 marks it OPTIONAL)Related