Skip to content
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

Lack of NTLMSSP_NEGOTIATE_VERSION and offset calculation #62

Closed
filipnavara opened this issue Feb 21, 2022 · 4 comments · Fixed by #65
Closed

Lack of NTLMSSP_NEGOTIATE_VERSION and offset calculation #62

filipnavara opened this issue Feb 21, 2022 · 4 comments · Fixed by #65

Comments

@filipnavara
Copy link

filipnavara commented Feb 21, 2022

The code seems to assume that the MIC offset is shifted down 8 bytes if NTLMSSP_NEGOTIATE_VERSION flag is not present. That doesn't seem to be in line with the Microsoft specification which always lists it as present, just being set to zero bytes. This discrepancy causes the MIC to be placed at a wrong offset and thus inadverently fail the integrity check.

I discovered it when comparing the macOS, Windows and this implementation. The MIC generation was explicitly enabled for the test through the private SPNEGO inquiry (https://github.com/dotnet/runtime/pull/65627/files#diff-c67e0117ce4bb818f2a2cc2c01ea9b2058c1a63b846af571ed2d59a2db9d33ffR411)

@filipnavara
Copy link
Author

I cross-checked with some other open source implementations:

There's a chance that the official specification is incorrect so more testing is necessary. However, setting NTLMSSP_NEGOTIATE_VERSION in NTLMSSP_DEFAULT_CLIENT_FLAGS should be on the safe side for interoperability with any recent system while matching the offsets in the official specification.

@filipnavara
Copy link
Author

filipnavara commented Feb 23, 2022

Tested against Windows Server 2022 and it confirms that the official specification is correct and the MIC offset is fixed regardless of NTLMSSP_NEGOTIATE_VERSION flag. Wireshark logs:

The server unilaterally sends the NTLMSSP_NEGOTIATE_VERSION flag in CHALLENGE_MESSAGE though which causes the AUTHENTICATE_MESSAGE is be built with the flag set in gss-ntlmssp. As long as the server does that it masks the offset calculation bug.

@filipnavara
Copy link
Author

I recommend evaluating this with extra scrutiny. So far every non-Windows implementation of NTLM (gss-ntlmssp, Apple, Heimdal, MailKit, FreeRDP, Wireshark analyzer) that I tested so far was not matching specification. That said, some of the implementations share heritage (Heimdal & Apple) and others could have simply copied the bug when the official specification was not available. Most of the implementation also never run into the code path for various reasons (eg. Apple always negotiates NTLMSSP_NEGOTIATE_VERSION, newer Windows Server always sends NTLMSSP_NEGOTIATE_VERSION in the challenge message). The safe fix is to always use NTLMSSP_NEGOTIATE_VERSION in the negotiation if MIC is present.

@simo5
Copy link
Collaborator

simo5 commented Feb 23, 2022

I think you are actually right, in the MS-NLMP document, which this implementation is based on, and I maintain is the most correct independent implementation, it says always:

Version (8 bytes): A VERSION structure (as defined in section 2.2.2.10) that SHOULD<9> be
populated only when the NTLMSSP_NEGOTIATE_VERSION flag is set in the NegotiateFlags field.

I mistakenly assumed this meant the structure would be omitted when the flag was not present, but that is not the case, the language just says "populated", which means the structure should alays be present but zeroed when the version is not requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants