Repository navigation
Pick the mechanism from the server's preference, not the client's - #309
Open
Pushpenderrathore wants to merge 1 commit into
Open
Pushpenderrathore wants to merge 1 commit into
Pushpenderrathore wants to merge 1 commit 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.
This was referenced Oct 3, 2026
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
Addresses #304.
Provider::Multi::Authenticator#processrouted each NegTokenInit by reading only the client's first-listed mechanism, so a client (or an on-path attacker rewriting the mechTypeList before signing was in effect) that reordered the list could steer the server to a weaker sub-provider without removing any mechanism. On a server built withMulti.new([kerberos_provider, ntlm_provider]), a client-asserted[NTLM, Kerberos]was routed to NTLM even though both sides supported Kerberos.Walk the full mechTypeList, pick the server's most-preferred advertised mechanism that the client also offers, and route to that. When that choice differs from the mechanism the client's optimistic mechToken was built for, reply with a NegTokenResp carrying
accept-incompleteandsupportedMechper RFC 4178 section 4.2.2 so the client resends a token for the server-selected mechanism.What this is and is not
This is server-side routing hardening that prevents client ordering from forcing a weaker common mechanism. It is not a replacement for a
mechListMICverifier: an on-path attacker who rewrites the client's mechTypeList before signing is in effect can still drop mechanisms the client would otherwise have offered. Full integrity for the negotiated mechanism list requires computing and verifying themechListMIC(RFC 4178 §5.1), which is tracked separately on #304 and left for a follow-up.Wire-level demonstration
A localhost MitM harness sends
[Kerberos, NTLM]from the client to a transparent TCP proxy, which rewrites the mechTypeList to[NTLM, Kerberos]and replaces the Kerberos optimistic mechToken with an NTLM Type 1 message, then forwards the resulting SMB2 SessionSetup to aMulti(Kerberos, NTLM)ruby_smb server on the other side.Same bytes on the wire in both runs. Only
lib/ruby_smb/gss/provider/multi.rbis swapped between runs:1.3.6.1.4.1.311.2.2.101.2.840.113554.1.2.2Before (upstream):
After (this branch):
Routing matrix
With server advertisement
[Kerberos, NTLM]:[Kerberos, NTLM][NTLM, Kerberos]accept-incomplete+supportedMech = Kerberos, awaits new token[NTLM][Kerberos][NEGOEX](no overlap)[](empty)Continuation after
accept-incompleteCovered by a new spec: client lists
[NTLM, Kerberos], server respondsaccept-incompletenaming Kerberos, client re-sends a NegTokenResp carrying a Kerberos token, which is dispatched to the Kerberos sub-provider'son_mech_tokenas if it had been named first.Verification Steps
bundle exec rspec spec/lib/ruby_smb/gss/provider/multi_spec.rbpasses with the matrix + continuation specs addedclient_mech_oidsreturns the exact OID strings in client-listed order for[Kerberos, NTLM],[NTLM, Kerberos],[NTLM],[Kerberos]multi.rbbetween runs reproduces the downgrade on upstream/master and refuses it on this branch (output above)gss_initnow delegates togss_init_listso previous call sites are byte-identical)Test Evidence
New describe blocks in
spec/lib/ruby_smb/gss/provider/multi_spec.rb:#process when a client offers more than one mechanismcovers the six matrix rows above.#process after replying accept-incomplete to a reordered clientexercises the two-leg continuation.Related