libfreerdp-sspi: improve server-side NTLM message parsing

This commit is contained in:
Marc-André Moreau 2012-03-18 18:14:20 -04:00
parent 40357d2c31
commit 8d82f15309
5 changed files with 176 additions and 7 deletions

View File

@ -86,6 +86,13 @@ void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
context->WorkstationLength = (uint32) size;
}
void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
{
size_t size;
context->TargetName.pvBuffer = (uint16*) freerdp_uniconv_out(context->uniconv, TargetName, &size);
context->TargetName.cbBuffer = (uint32) size;
}
NTLM_CONTEXT* ntlm_ContextNew()
{
NTLM_CONTEXT* context;
@ -199,6 +206,8 @@ SECURITY_STATUS ntlm_AcceptSecurityContext(CredHandle* phCredential, CtxtHandle*
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
ntlm_SetContextTargetName(context, "FreeRDP");
sspi_SecureHandleSetLowerPointer(phNewContext, context);
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
}

View File

@ -115,6 +115,8 @@ typedef struct _NTLM_CONTEXT NTLM_CONTEXT;
NTLM_CONTEXT* ntlm_ContextNew();
void ntlm_ContextFree(NTLM_CONTEXT* context);
//#define WITH_DEBUG_NTLM 1
#ifdef WITH_DEBUG_NLA
#define WITH_DEBUG_NTLM
#endif
#endif /* FREERDP_SSPI_NTLM_PRIVATE_H */

View File

@ -383,7 +383,7 @@ int ntlm_compute_av_pairs_length(NTLM_CONTEXT* context)
length += av_pairs->ChannelBindings.length + 4;
if (av_pairs->TargetName.length > 0)
length += av_pairs->TargetName.length + 4;
length += av_pairs->TargetName.length + 4;
length += 4;
@ -421,6 +421,40 @@ void ntlm_populate_av_pairs(NTLM_CONTEXT* context)
ntlm_output_av_pairs(context, &context->TargetInfo);
}
/**
* Populate array of AV_PAIRs (server).\n
* AV_PAIR @msdn{cc236646}
* @param NTLM context
*/
char* test_NbDomainName = "FREERDP";
char* test_NbComputerName = "FREERDP";
char* test_DnsDomainName = "FreeRDP";
char* test_DnsComputerName = "FreeRDP";
void ntlm_populate_server_av_pairs(NTLM_CONTEXT* context)
{
int length;
size_t size;
AV_PAIRS* av_pairs = context->av_pairs;
av_pairs->NbDomainName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_NbDomainName, &size);
av_pairs->NbDomainName.length = (uint16) size;
av_pairs->NbComputerName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_NbComputerName, &size);
av_pairs->NbComputerName.length = (uint16) size;
av_pairs->DnsDomainName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_DnsDomainName, &size);
av_pairs->DnsDomainName.length = (uint16) size;
av_pairs->DnsComputerName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_DnsComputerName, &size);
av_pairs->DnsComputerName.length = (uint16) size;
length = ntlm_compute_av_pairs_length(context) + 4;
sspi_SecBufferAlloc(&context->TargetInfo, length);
ntlm_output_av_pairs(context, &context->TargetInfo);
}
/**
* Print array of AV_PAIRs.\n
* AV_PAIR @msdn{cc236646}

View File

@ -29,6 +29,7 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
void ntlm_input_av_pairs(NTLM_CONTEXT* context, STREAM* s);
void ntlm_output_av_pairs(NTLM_CONTEXT* context, SecBuffer* buffer);
void ntlm_populate_av_pairs(NTLM_CONTEXT* context);
void ntlm_populate_server_av_pairs(NTLM_CONTEXT* context);
void ntlm_print_av_pairs(NTLM_CONTEXT* context);
void ntlm_free_av_pairs(NTLM_CONTEXT* context);

View File

@ -327,6 +327,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buf
uint16 TargetInfoMaxLen;
uint32 TargetInfoBufferOffset;
ntlm_generate_client_challenge(context);
s = stream_new(0);
stream_attach(s, buffer->pvBuffer, buffer->cbBuffer);
@ -499,6 +501,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu
{
STREAM* s;
int length;
uint32 PayloadOffset;
uint16 TargetNameLen;
uint8* TargetNameBuffer;
uint32 TargetNameBufferOffset;
@ -506,19 +509,51 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu
uint8* TargetInfoBuffer;
uint32 TargetInfoBufferOffset;
/* Server Challenge */
ntlm_generate_server_challenge(context);
/* Timestamp */
ntlm_generate_timestamp(context);
/* TargetInfo */
ntlm_populate_server_av_pairs(context);
s = stream_new(0);
stream_attach(s, buffer->pvBuffer, buffer->cbBuffer);
stream_write(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */
stream_write_uint32(s, MESSAGE_TYPE_CHALLENGE); /* MessageType */
TargetNameLen = context->TargetName.cbBuffer;
TargetNameBuffer = context->TargetName.pvBuffer;
if (context->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
{
TargetNameLen = context->TargetName.cbBuffer;
TargetNameBuffer = context->TargetName.pvBuffer;
}
else
{
TargetNameLen = 0;
TargetNameBuffer = NULL;
}
TargetInfoLen = context->TargetInfo.cbBuffer;
TargetInfoBuffer = context->TargetInfo.pvBuffer;
context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
TargetNameBufferOffset = 56;
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
{
TargetInfoLen = context->TargetInfo.cbBuffer;
TargetInfoBuffer = context->TargetInfo.pvBuffer;
}
else
{
TargetInfoLen = 0;
TargetInfoBuffer = NULL;
}
PayloadOffset = 48;
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
PayloadOffset += 8;
TargetNameBufferOffset = PayloadOffset;
TargetInfoBufferOffset = TargetNameBufferOffset + TargetNameLen;
/* TargetNameFields (8 bytes) */
@ -577,6 +612,15 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu
printf("\n");
#endif
/* Initialize RC4 seal state */
ntlm_init_rc4_seal_states(context);
#ifdef WITH_DEBUG_NTLM
printf("ServerChallenge\n");
freerdp_hexdump(context->ServerChallenge, 8);
printf("\n");
#endif
context->state = NTLM_STATE_AUTHENTICATE;
stream_detach(s);
@ -594,21 +638,27 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
uint32 NegotiateFlags;
uint16 DomainNameLen;
uint16 DomainNameMaxLen;
uint8* DomainNameBuffer;
uint32 DomainNameBufferOffset;
uint16 UserNameLen;
uint16 UserNameMaxLen;
uint8* UserNameBuffer;
uint32 UserNameBufferOffset;
uint16 WorkstationLen;
uint16 WorkstationMaxLen;
uint8* WorkstationBuffer;
uint32 WorkstationBufferOffset;
uint16 LmChallengeResponseLen;
uint16 LmChallengeResponseMaxLen;
uint8* LmChallengeResponseBuffer;
uint32 LmChallengeResponseBufferOffset;
uint16 NtChallengeResponseLen;
uint16 NtChallengeResponseMaxLen;
uint8* NtChallengeResponseBuffer;
uint32 NtChallengeResponseBufferOffset;
uint16 EncryptedRandomSessionKeyLen;
uint16 EncryptedRandomSessionKeyMaxLen;
uint8* EncryptedRandomSessionKeyBuffer;
uint32 EncryptedRandomSessionKeyBufferOffset;
s = stream_new(0);
@ -665,6 +715,13 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
if (NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{
/* Only present if NTLMSSP_NEGOTIATE_VERSION is set */
#ifdef WITH_DEBUG_NTLM
printf("Version (length = 8)\n");
freerdp_hexdump(s->p, 8);
printf("\n");
#endif
stream_seek(s, 8); /* Version (8 bytes) */
}
@ -679,6 +736,72 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
printf("\n");
#endif
/* DomainName */
if (DomainNameLen > 0)
{
DomainNameBuffer = s->data + DomainNameBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("DomainName (length = %d, offset = %d)\n", DomainNameLen, DomainNameBufferOffset);
freerdp_hexdump(DomainNameBuffer, DomainNameLen);
printf("\n");
#endif
}
/* UserName */
if (UserNameLen > 0)
{
UserNameBuffer = s->data + UserNameBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("UserName (length = %d, offset = %d)\n", UserNameLen, UserNameBufferOffset);
freerdp_hexdump(UserNameBuffer, UserNameLen);
printf("\n");
#endif
}
/* Workstation */
if (WorkstationLen > 0)
{
WorkstationBuffer = s->data + WorkstationBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("Workstation (length = %d, offset = %d)\n", WorkstationLen, WorkstationBufferOffset);
freerdp_hexdump(WorkstationBuffer, WorkstationLen);
printf("\n");
#endif
}
/* LmChallengeResponse */
if (LmChallengeResponseLen > 0)
{
LmChallengeResponseBuffer = s->data + LmChallengeResponseBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("LmChallengeResponse (length = %d, offset = %d)\n", LmChallengeResponseLen, LmChallengeResponseBufferOffset);
freerdp_hexdump(LmChallengeResponseBuffer, LmChallengeResponseLen);
printf("\n");
#endif
}
/* NtChallengeResponse */
if (NtChallengeResponseLen > 0)
{
NtChallengeResponseBuffer = s->data + NtChallengeResponseBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("NtChallengeResponse (length = %d, offset = %d)\n", NtChallengeResponseLen, NtChallengeResponseBufferOffset);
freerdp_hexdump(NtChallengeResponseBuffer, NtChallengeResponseLen);
printf("\n");
#endif
}
/* EncryptedRandomSessionKey */
if (EncryptedRandomSessionKeyLen > 0)
{
EncryptedRandomSessionKeyBuffer = s->data + EncryptedRandomSessionKeyBufferOffset;
#ifdef WITH_DEBUG_NTLM
printf("EncryptedRandomSessionKey (length = %d, offset = %d)\n", EncryptedRandomSessionKeyLen, EncryptedRandomSessionKeyBufferOffset);
freerdp_hexdump(EncryptedRandomSessionKeyBuffer, EncryptedRandomSessionKeyLen);
printf("\n");
#endif
}
context->state = NTLM_STATE_FINAL;
stream_detach(s);