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:
parent
aa07efeb18
commit
85e49aa601
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user