libwinpr-sspi: get partial server-side NLA functionality with mstsc.exe as a client
This commit is contained in:
parent
bf559e37eb
commit
6d7f1e427c
@ -537,6 +537,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
|||||||
status = SEC_I_CONTINUE_NEEDED;
|
status = SEC_I_CONTINUE_NEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
|
||||||
|
{
|
||||||
|
printf("AcceptSecurityContext status: 0x%08X\n", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* send authentication token */
|
/* send authentication token */
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_CREDSSP
|
#ifdef WITH_DEBUG_CREDSSP
|
||||||
|
@ -86,12 +86,12 @@ NTLM_CONTEXT* ntlm_ContextNew()
|
|||||||
|
|
||||||
if (context != NULL)
|
if (context != NULL)
|
||||||
{
|
{
|
||||||
context->ntlm_v2 = TRUE;
|
context->ntlm_v2 = FALSE;
|
||||||
context->NegotiateFlags = 0;
|
context->NegotiateFlags = 0;
|
||||||
context->SendVersionInfo = TRUE;
|
context->SendVersionInfo = TRUE;
|
||||||
context->LmCompatibilityLevel = 3;
|
context->LmCompatibilityLevel = 3;
|
||||||
context->state = NTLM_STATE_INITIAL;
|
context->state = NTLM_STATE_INITIAL;
|
||||||
context->SuppressExtendedProtection = 1;
|
context->SuppressExtendedProtection = TRUE;
|
||||||
context->av_pairs = (AV_PAIRS*) malloc(sizeof(AV_PAIRS));
|
context->av_pairs = (AV_PAIRS*) malloc(sizeof(AV_PAIRS));
|
||||||
ZeroMemory(context->av_pairs, sizeof(AV_PAIRS));
|
ZeroMemory(context->av_pairs, sizeof(AV_PAIRS));
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,16 @@ struct _NTLM_VERSION_INFO
|
|||||||
};
|
};
|
||||||
typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO;
|
typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO;
|
||||||
|
|
||||||
|
struct _NTLM_RESTRICTION_ENCODING
|
||||||
|
{
|
||||||
|
UINT32 Size;
|
||||||
|
UINT32 Z4;
|
||||||
|
UINT32 IntegrityLevel;
|
||||||
|
UINT32 SubjectIntegrityLevel;
|
||||||
|
BYTE MachineId[32];
|
||||||
|
};
|
||||||
|
typedef struct _NTLM_RESTRICTION_ENCODING NTLM_RESTRICTION_ENCODING;
|
||||||
|
|
||||||
struct _NTLM_RESPONSE
|
struct _NTLM_RESPONSE
|
||||||
{
|
{
|
||||||
BYTE Response[24];
|
BYTE Response[24];
|
||||||
@ -236,7 +246,7 @@ struct _NTLM_CONTEXT
|
|||||||
NTLM_STATE state;
|
NTLM_STATE state;
|
||||||
int SendSeqNum;
|
int SendSeqNum;
|
||||||
int RecvSeqNum;
|
int RecvSeqNum;
|
||||||
int SendVersionInfo;
|
BOOL SendVersionInfo;
|
||||||
BOOL confidentiality;
|
BOOL confidentiality;
|
||||||
RC4_KEY SendRc4Seal;
|
RC4_KEY SendRc4Seal;
|
||||||
RC4_KEY RecvRc4Seal;
|
RC4_KEY RecvRc4Seal;
|
||||||
|
@ -219,8 +219,8 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
|||||||
context->NegotiateMessage.BufferType = buffer->BufferType;
|
context->NegotiateMessage.BufferType = buffer->BufferType;
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_NTLM
|
#ifdef WITH_DEBUG_NTLM
|
||||||
printf("NEGOTIATE_MESSAGE (length = %d)\n", length);
|
printf("NEGOTIATE_MESSAGE (length = %d)\n", (int) context->NegotiateMessage.cbBuffer);
|
||||||
winpr_HexDump(s->data, length);
|
winpr_HexDump(context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
ntlm_print_negotiate_flags(message.NegotiateFlags);
|
ntlm_print_negotiate_flags(message.NegotiateFlags);
|
||||||
@ -353,7 +353,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
|
|||||||
/* TargetNameFields (8 bytes) */
|
/* TargetNameFields (8 bytes) */
|
||||||
ntlm_read_message_fields(s, &(message.TargetName));
|
ntlm_read_message_fields(s, &(message.TargetName));
|
||||||
|
|
||||||
StreamRead_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */
|
StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */
|
||||||
|
context->NegotiateFlags = message.NegotiateFlags;
|
||||||
|
|
||||||
StreamRead(s, message.ServerChallenge, 8); /* ServerChallenge (8 bytes) */
|
StreamRead(s, message.ServerChallenge, 8); /* ServerChallenge (8 bytes) */
|
||||||
CopyMemory(context->ServerChallenge, message.ServerChallenge, 8);
|
CopyMemory(context->ServerChallenge, message.ServerChallenge, 8);
|
||||||
@ -602,11 +603,17 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
|||||||
{
|
{
|
||||||
PStream s;
|
PStream s;
|
||||||
int length;
|
int length;
|
||||||
UINT32 flags = 0;
|
UINT32 flags;
|
||||||
|
UINT32 MicOffset;
|
||||||
|
NTLM_AV_PAIR* AvFlags;
|
||||||
NTLMv2_RESPONSE response;
|
NTLMv2_RESPONSE response;
|
||||||
UINT32 PayloadBufferOffset;
|
UINT32 PayloadBufferOffset;
|
||||||
NTLM_AUTHENTICATE_MESSAGE message;
|
NTLM_AUTHENTICATE_MESSAGE message;
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
MicOffset = 0;
|
||||||
|
AvFlags = NULL;
|
||||||
|
|
||||||
ZeroMemory(&message, sizeof(message));
|
ZeroMemory(&message, sizeof(message));
|
||||||
s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer);
|
s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer);
|
||||||
|
|
||||||
@ -664,12 +671,16 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
|||||||
|
|
||||||
if (message.NtChallengeResponse.Len > 0)
|
if (message.NtChallengeResponse.Len > 0)
|
||||||
{
|
{
|
||||||
NTLM_AV_PAIR* AvFlags;
|
|
||||||
|
|
||||||
PStream s = PStreamAllocAttach(message.NtChallengeResponse.Buffer, message.NtChallengeResponse.Len);
|
PStream s = PStreamAllocAttach(message.NtChallengeResponse.Buffer, message.NtChallengeResponse.Len);
|
||||||
ntlm_read_ntlm_v2_response(s, &response);
|
ntlm_read_ntlm_v2_response(s, &response);
|
||||||
PStreamFreeDetach(s);
|
PStreamFreeDetach(s);
|
||||||
|
|
||||||
|
context->NtChallengeResponse.pvBuffer = message.NtChallengeResponse.Buffer;
|
||||||
|
context->NtChallengeResponse.cbBuffer = message.NtChallengeResponse.Len;
|
||||||
|
|
||||||
|
context->TargetInfo.pvBuffer = (void*) response.Challenge.AvPairs;
|
||||||
|
context->TargetInfo.cbBuffer = message.NtChallengeResponse.Len - (28 + 16);
|
||||||
|
|
||||||
CopyMemory(context->ClientChallenge, response.Challenge.ClientChallenge, 8);
|
CopyMemory(context->ClientChallenge, response.Challenge.ClientChallenge, 8);
|
||||||
|
|
||||||
AvFlags = ntlm_av_pair_get(response.Challenge.AvPairs, MsvAvFlags);
|
AvFlags = ntlm_av_pair_get(response.Challenge.AvPairs, MsvAvFlags);
|
||||||
@ -682,25 +693,23 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
|||||||
ntlm_read_message_fields_buffer(s, &(message.EncryptedRandomSessionKey));
|
ntlm_read_message_fields_buffer(s, &(message.EncryptedRandomSessionKey));
|
||||||
CopyMemory(context->EncryptedRandomSessionKey, message.EncryptedRandomSessionKey.Buffer, 16);
|
CopyMemory(context->EncryptedRandomSessionKey, message.EncryptedRandomSessionKey.Buffer, 16);
|
||||||
|
|
||||||
StreamSetOffset(s, PayloadBufferOffset);
|
|
||||||
|
|
||||||
if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
|
|
||||||
{
|
|
||||||
StreamRead(s, message.MessageIntegrityCheck, 16);
|
|
||||||
PayloadBufferOffset += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* move to end of stream, incorrectly assumes the EncryptedRandomSessionKey buffer is last */
|
|
||||||
StreamSetOffset(s, message.EncryptedRandomSessionKey.BufferOffset + message.EncryptedRandomSessionKey.Len);
|
|
||||||
|
|
||||||
length = StreamSize(s);
|
length = StreamSize(s);
|
||||||
sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
|
sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
|
||||||
CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length);
|
CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length);
|
||||||
buffer->cbBuffer = length;
|
buffer->cbBuffer = length;
|
||||||
|
|
||||||
|
StreamSetOffset(s, PayloadBufferOffset);
|
||||||
|
|
||||||
|
if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
|
||||||
|
{
|
||||||
|
MicOffset = StreamGetOffset(s);
|
||||||
|
StreamRead(s, message.MessageIntegrityCheck, 16);
|
||||||
|
PayloadBufferOffset += 16;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_NTLM
|
#ifdef WITH_DEBUG_NTLM
|
||||||
printf("AUTHENTICATE_MESSAGE (length = %d)\n", length);
|
printf("AUTHENTICATE_MESSAGE (length = %d)\n", (int) context->AuthenticateMessage.cbBuffer);
|
||||||
winpr_HexDump(s->data, length);
|
winpr_HexDump(context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
||||||
@ -751,6 +760,25 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
|||||||
/* ExportedSessionKey */
|
/* ExportedSessionKey */
|
||||||
ntlm_generate_exported_session_key(context);
|
ntlm_generate_exported_session_key(context);
|
||||||
|
|
||||||
|
if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
|
||||||
|
{
|
||||||
|
ZeroMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[MicOffset], 16);
|
||||||
|
ntlm_compute_message_integrity_check(context);
|
||||||
|
CopyMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[MicOffset], message.MessageIntegrityCheck, 16);
|
||||||
|
|
||||||
|
if (memcmp(context->MessageIntegrityCheck, message.MessageIntegrityCheck, 16) != 0)
|
||||||
|
{
|
||||||
|
printf("Message Integrity Check (MIC) verification failed!\n");
|
||||||
|
|
||||||
|
printf("Expected MIC:\n");
|
||||||
|
winpr_HexDump(context->MessageIntegrityCheck, 16);
|
||||||
|
printf("Actual MIC:\n");
|
||||||
|
winpr_HexDump(message.MessageIntegrityCheck, 16);
|
||||||
|
|
||||||
|
//return SEC_E_MESSAGE_ALTERED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate signing keys */
|
/* Generate signing keys */
|
||||||
ntlm_generate_client_signing_key(context);
|
ntlm_generate_client_signing_key(context);
|
||||||
ntlm_generate_server_signing_key(context);
|
ntlm_generate_server_signing_key(context);
|
||||||
|
Loading…
Reference in New Issue
Block a user