From 2ef315820f6148917a385ce6a7a102829cf87302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 11 Dec 2011 16:53:24 -0500 Subject: [PATCH] libfreerdp-core: apply NTLMv2 authentication patch by Dmitrij Jasnov --- libfreerdp-core/credssp.c | 11 +++-- libfreerdp-core/ntlmssp.c | 101 ++++++++++++++++++++++++++++++++++++-- libfreerdp-core/ntlmssp.h | 1 + libfreerdp-utils/args.c | 1 + 4 files changed, 107 insertions(+), 7 deletions(-) diff --git a/libfreerdp-core/credssp.c b/libfreerdp-core/credssp.c index 6576cd460..095b4ad54 100644 --- a/libfreerdp-core/credssp.c +++ b/libfreerdp-core/credssp.c @@ -90,9 +90,17 @@ int credssp_ntlmssp_init(rdpCredssp* credssp) } } + if (settings->ntlm_version == 2) + ntlmssp->ntlm_v2 = 1; + ntlmssp_set_password(ntlmssp, settings->password); ntlmssp_set_username(ntlmssp, settings->username); + if (ntlmssp->ntlm_v2) + { + ntlmssp_set_workstation(ntlmssp, "WORKSTATION"); + } + if (settings->domain != NULL) { if (strlen(settings->domain) > 0) @@ -106,9 +114,6 @@ int credssp_ntlmssp_init(rdpCredssp* credssp) ntlmssp_generate_client_challenge(ntlmssp); ntlmssp_generate_random_session_key(ntlmssp); ntlmssp_generate_exported_session_key(ntlmssp); - - if (settings->ntlm_version == 2) - ntlmssp->ntlm_v2 = 1; return 1; } diff --git a/libfreerdp-core/ntlmssp.c b/libfreerdp-core/ntlmssp.c index 20ddc23bf..0e462d68a 100644 --- a/libfreerdp-core/ntlmssp.c +++ b/libfreerdp-core/ntlmssp.c @@ -174,6 +174,22 @@ void ntlmssp_set_password(NTLMSSP* ntlmssp, char* password) } } +/** + * Set NTLMSSP workstation. + * @param ntlmssp + * @param workstation workstation + */ + +void ntlmssp_set_workstation(NTLMSSP* ntlmssp, char* workstation) +{ + freerdp_blob_free(&ntlmssp->workstation); + + if (workstation != NULL) + { + ntlmssp->workstation.data = freerdp_uniconv_out(ntlmssp->uniconv, workstation, (size_t*) &(ntlmssp->workstation.length)); + } +} + /** * Generate client challenge (8-byte nonce). * @param ntlmssp @@ -245,6 +261,15 @@ void ntlmssp_generate_timestamp(NTLMSSP* ntlmssp) return; } } + else + { + if (ntlmssp->av_pairs->Timestamp.length != 8) + { + ntlmssp->av_pairs->Timestamp.length = 8; + ntlmssp->av_pairs->Timestamp.value = xmalloc(ntlmssp->av_pairs->Timestamp.length); + } + memcpy(ntlmssp->av_pairs->Timestamp.value, ntlmssp->timestamp, 8); + } } /** @@ -586,6 +611,10 @@ void ntlmssp_compute_ntlm_v2_response(NTLMSSP* ntlmssp) freerdp_hexdump(ntlmssp->domain.data, ntlmssp->domain.length); printf("\n"); + printf("Workstation (length = %d)\n", ntlmssp->workstation.length); + freerdp_hexdump(ntlmssp->workstation.data, ntlmssp->workstation.length); + printf("\n"); + printf("NTOWFv2, NTLMv2 Hash\n"); freerdp_hexdump(ntlm_v2_hash, 16); printf("\n"); @@ -596,7 +625,7 @@ void ntlmssp_compute_ntlm_v2_response(NTLMSSP* ntlmssp) blob[1] = 1; /* HighRespType (1 byte) */ /* Reserved1 (2 bytes) */ /* Reserved2 (4 bytes) */ - memcpy(&blob[8], ntlmssp->timestamp, 8); /* Timestamp (8 bytes) */ + memcpy(&blob[8], ntlmssp->av_pairs->Timestamp.value, 8); /* Timestamp (8 bytes) */ memcpy(&blob[16], ntlmssp->client_challenge, 8); /* ClientChallenge (8 bytes) */ /* Reserved3 (4 bytes) */ memcpy(&blob[28], ntlmssp->target_info.data, ntlmssp->target_info.length); @@ -701,12 +730,65 @@ static void ntlmssp_output_restriction_encoding(NTLMSSP* ntlmssp) stream_write_uint8(s, 1); stream_write_zero(s, 3); - stream_write_uint32(s, 0x20000000); /* SubjectIntegrityLevel */ + stream_write_uint32(s, 0x00002000); /* SubjectIntegrityLevel */ stream_write(s, machineID, 32); /* MachineID */ xfree(s); } +/** + * Output TargetName.\n + * @param ntlmssp + */ + +void ntlmssp_output_target_name(NTLMSSP* ntlmssp) +{ + STREAM* s = stream_new(0); + AV_PAIR* target_name = &ntlmssp->av_pairs->TargetName; + + /* + * TODO: No idea what should be set here (observed MsvAvTargetName = MsvAvDnsComputerName or + * MsvAvTargetName should be the name of the service be accessed after authentication) + * here used: "TERMSRV/192.168.0.123" in unicode (Dmitrij Jasnov) + */ + uint8 name[42] = + "\x54\x00\x45\x00\x52\x00\x4d\x00\x53\x00\x52\x00\x56\x00\x2f\x00\x31\x00\x39\x00\x32" + "\x00\x2e\x00\x31\x00\x36\x00\x38\x00\x2e\x00\x30\x00\x2e\x00\x31\x00\x32\x00\x33\x00"; + + target_name->length = 42; + target_name->value = (uint8*) xmalloc(target_name->length); + + s->data = target_name->value; + s->size = target_name->length; + s->p = s->data; + + stream_write(s, name, target_name->length); + + xfree(s); +} + +/** + * Output ChannelBindings.\n + * @param ntlmssp + */ + +void ntlmssp_output_channel_bindings(NTLMSSP* ntlmssp) +{ + STREAM* s = stream_new(0); + AV_PAIR* channel_bindings = &ntlmssp->av_pairs->ChannelBindings; + + channel_bindings->value = (uint8*) xmalloc(48); + channel_bindings->length = 16; + + s->data = channel_bindings->value; + s->size = channel_bindings->length; + s->p = s->data; + + stream_write_zero(s, 16); /* an all-zero value of the hash is used to indicate absence of channel bindings */ + + xfree(s); +} + /** * Populate array of AV_PAIRs.\n * AV_PAIR @msdn{cc236646} @@ -725,6 +807,12 @@ void ntlmssp_populate_av_pairs(NTLMSSP* ntlmssp) /* Restriction_Encoding */ ntlmssp_output_restriction_encoding(ntlmssp); + /* TargetName */ + ntlmssp_output_target_name(ntlmssp); + + /* ChannelBindings */ + ntlmssp_output_channel_bindings(ntlmssp); + s = stream_new(0); s->data = xmalloc(ntlmssp->target_info.length + 512); s->p = s->data; @@ -1194,7 +1282,8 @@ void ntlmssp_send_negotiate_message(NTLMSSP* ntlmssp, STREAM* s) if (ntlmssp->ntlm_v2) { - /* observed: B7 82 08 E2 (0xE20882B7) */ + DEBUG_NLA("Negotiating NTLMv2"); + /* observed: B7 82 08 E2 (0xE20882B7) (Dmitrij Jasnov) */ negotiateFlags |= NTLMSSP_NEGOTIATE_56; negotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH; negotiateFlags |= NTLMSSP_NEGOTIATE_128; @@ -1516,10 +1605,13 @@ void ntlmssp_send_authenticate_message(NTLMSSP* ntlmssp, STREAM* s) } if (ntlmssp->ntlm_v2) - PayloadBufferOffset = 88; /* starting buffer offset */ + PayloadBufferOffset = 80; /* starting buffer offset */ else PayloadBufferOffset = 64; /* starting buffer offset */ + if (negotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + PayloadBufferOffset += 8; + DomainNameBufferOffset = PayloadBufferOffset; UserNameBufferOffset = DomainNameBufferOffset + DomainNameLen; WorkstationBufferOffset = UserNameBufferOffset + UserNameLen; @@ -1669,6 +1761,7 @@ void ntlmssp_send_authenticate_message(NTLMSSP* ntlmssp, STREAM* s) s->p = mic_offset; stream_write(s, ntlmssp->message_integrity_check, 16); + s->p = s->data + length; #ifdef WITH_DEBUG_NLA printf("MessageIntegrityCheck (length = 16)\n"); diff --git a/libfreerdp-core/ntlmssp.h b/libfreerdp-core/ntlmssp.h index aa9745899..a9dce6725 100644 --- a/libfreerdp-core/ntlmssp.h +++ b/libfreerdp-core/ntlmssp.h @@ -117,6 +117,7 @@ typedef struct _NTLMSSP NTLMSSP; void ntlmssp_set_username(NTLMSSP* ntlmssp, char* username); void ntlmssp_set_domain(NTLMSSP* ntlmssp, char* domain); void ntlmssp_set_password(NTLMSSP* ntlmssp, char* password); +void ntlmssp_set_workstation(NTLMSSP* ntlmssp, char* workstation); void ntlmssp_generate_client_challenge(NTLMSSP* ntlmssp); void ntlmssp_generate_key_exchange_key(NTLMSSP* ntlmssp); diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index b2356efb3..84ea4aeb3 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -92,6 +92,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --no-rdp: disable Standard RDP encryption\n" " --no-tls: disable TLS encryption\n" " --no-nla: disable network level authentication\n" + " --ntlm: force NTLM authentication protocol version (1 or 2)\n" " --ignore-certificate: ignore verification of logon certificate\n" " --sec: force protocol security (rdp, tls or nla)\n" " --version: print version information\n"