fix: server side ntlmv2 implementation

- in the case no mic was present, but the user was found,
  the enterd password was ignored and the user authenticated
This commit is contained in:
Martin Haimberger 2020-04-15 11:43:45 +02:00 committed by akallabeth
parent aa07efeb18
commit 85e49aa601
3 changed files with 34 additions and 6 deletions

View File

@ -261,6 +261,7 @@ struct _NTLM_CONTEXT
SecBuffer NtChallengeResponse;
SecBuffer LmChallengeResponse;
NTLMv2_RESPONSE NTLMv2Response;
BYTE NtProofString[16];
BYTE Timestamp[8];
BYTE ChallengeTimestamp[8];
BYTE ServerChallenge[8];

View File

@ -415,7 +415,6 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
{
BYTE* blob;
BYTE nt_proof_str[WINPR_MD5_DIGEST_LENGTH];
SecBuffer ntlm_v2_temp;
SecBuffer ntlm_v2_temp_chal;
PSecBuffer TargetInfo;
@ -454,8 +453,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
CopyMemory(blob, context->ServerChallenge, 8);
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
(BYTE*)ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer, (BYTE*)nt_proof_str,
WINPR_MD5_DIGEST_LENGTH);
(BYTE*)ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer,
(BYTE*)context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
/* NtChallengeResponse, Concatenate NTProofStr with temp */
@ -463,12 +462,12 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
return -1;
blob = (BYTE*)context->NtChallengeResponse.pvBuffer;
CopyMemory(blob, nt_proof_str, 16);
CopyMemory(blob, context->NtProofString, 16);
CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
/* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
(BYTE*)nt_proof_str, WINPR_MD5_DIGEST_LENGTH, (BYTE*)context->SessionBaseKey,
WINPR_MD5_DIGEST_LENGTH);
(BYTE*)context->NtProofString, WINPR_MD5_DIGEST_LENGTH,
(BYTE*)context->SessionBaseKey, WINPR_MD5_DIGEST_LENGTH);
sspi_SecBufferFree(&ntlm_v2_temp);
sspi_SecBufferFree(&ntlm_v2_temp_chal);
return 1;

View File

@ -1180,6 +1180,34 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context)
return SEC_E_MESSAGE_ALTERED;
}
}
else
{
/* no mic message was present
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.
now check the NtProofString, to detect if the entered client password matches the
expected password.
*/
#ifdef WITH_DEBUG_NTLM
WLog_DBG(TAG, "No MIC present, using NtProofString for verification.");
#endif
if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
{
WLog_ERR(TAG, "NtProofString verification failed!");
#ifdef WITH_DEBUG_NTLM
WLog_ERR(TAG, "Expected NtProofString:");
winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, 16);
WLog_ERR(TAG, "Actual NtProofString:");
winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response, 16);
#endif
return SEC_E_LOGON_DENIED;
}
}
/* Generate signing keys */
ntlm_generate_client_signing_key(context);