diff --git a/include/winpr/credssp.h b/include/winpr/credssp.h index 2e690ccd0..f19c1c0c9 100644 --- a/include/winpr/credssp.h +++ b/include/winpr/credssp.h @@ -66,6 +66,7 @@ FREERDP_API void credssp_buffer_free(rdpCredssp* credssp); SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp); FREERDP_API void credssp_encode_ts_credentials(rdpCredssp* credssp); SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp); +SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp); FREERDP_API rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings); FREERDP_API void credssp_free(rdpCredssp* credssp); diff --git a/winpr/sspi/CredSSP/credssp.c b/winpr/sspi/CredSSP/credssp.c index 62b67104c..9a48e7b5e 100644 --- a/winpr/sspi/CredSSP/credssp.c +++ b/winpr/sspi/CredSSP/credssp.c @@ -100,10 +100,18 @@ void credssp_SetContextIdentity(rdpCredssp* context, char* user, char* domain, c context->identity.DomainLength = 0; } - context->identity.PasswordLength = strlen(password) * 2; - context->identity.Password = (uint16*) malloc(context->identity.PasswordLength); - MultiByteToWideChar(CP_ACP, 0, password, strlen(password), - (LPWSTR) context->identity.Password, context->identity.PasswordLength / 2); + if (password != NULL) + { + context->identity.PasswordLength = strlen(password) * 2; + context->identity.Password = (uint16*) malloc(context->identity.PasswordLength); + MultiByteToWideChar(CP_ACP, 0, password, strlen(password), + (LPWSTR) context->identity.Password, context->identity.PasswordLength / 2); + } + else + { + context->identity.Password = NULL; + context->identity.PasswordLength = 0; + } } /** @@ -522,16 +530,18 @@ int credssp_server_authenticate(rdpCredssp* credssp) have_pub_key_auth = true; - sspi_SecBufferFree(&credssp->negoToken); - credssp->negoToken.pvBuffer = NULL; - credssp->negoToken.cbBuffer = 0; - if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK) { printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n"); return 0; } + credssp_verify_public_key_echo(credssp); + + sspi_SecBufferFree(&credssp->negoToken); + credssp->negoToken.pvBuffer = NULL; + credssp->negoToken.cbBuffer = 0; + if (have_pub_key_auth) { uint8* p; @@ -591,6 +601,8 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (credssp_recv(credssp) < 0) return -1; + credssp_decrypt_ts_credentials(credssp); + if (status != SEC_E_OK) { printf("AcceptSecurityContext status: 0x%08X\n", status); @@ -647,19 +659,19 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp) SECURITY_STATUS status; length = credssp->pubKeyAuth.cbBuffer; - pub_key_auth = (uint8*) credssp->pubKeyAuth.pvBuffer; + pub_key_auth = (BYTE*) credssp->pubKeyAuth.pvBuffer; public_key_length = credssp->PublicKey.cbBuffer; Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */ Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature; - Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer); - memcpy(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer); + Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer); + CopyMemory(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer); Buffers[1].cbBuffer = length - Buffers[0].cbBuffer; - Buffers[1].pvBuffer = xmalloc(Buffers[1].cbBuffer); - memcpy(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer); + Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer); + CopyMemory(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer); Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; @@ -673,10 +685,11 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp) return status; } - public_key1 = (uint8*) credssp->PublicKey.pvBuffer; - public_key2 = (uint8*) Buffers[1].pvBuffer; + public_key1 = (BYTE*) credssp->PublicKey.pvBuffer; + public_key2 = (BYTE*) Buffers[1].pvBuffer; - public_key2[0]--; /* server echos the public key +1 */ + if (!credssp->server) + public_key2[0]--; /* server echos the public key +1 */ if (memcmp(public_key1, public_key2, public_key_length) != 0) { @@ -701,22 +714,22 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp) SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) { - uint8* p; + BYTE* p; SecBuffer Buffers[2]; SecBufferDesc Message; SECURITY_STATUS status; credssp_encode_ts_credentials(credssp); - Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */ - Buffers[1].BufferType = SECBUFFER_TOKEN; /* Signature */ + Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ + Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */ - Buffers[0].cbBuffer = credssp->ts_credentials.cbBuffer; - Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer); - memcpy(Buffers[0].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[0].cbBuffer); + Buffers[0].cbBuffer = 16; + Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer); - Buffers[1].cbBuffer = 16; - Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer); + Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer; + Buffers[1].pvBuffer = xmalloc(Buffers[1].cbBuffer); + CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer); Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; @@ -729,9 +742,9 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) if (status != SEC_E_OK) return status; - p = (uint8*) credssp->authInfo.pvBuffer; - memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */ - memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted TSCredentials */ + p = (BYTE*) credssp->authInfo.pvBuffer; + CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */ + CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted TSCredentials */ xfree(Buffers[0].pvBuffer); xfree(Buffers[1].pvBuffer); @@ -739,6 +752,45 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) return SEC_E_OK; } +SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp) +{ + BYTE* p; + SecBuffer Buffers[2]; + SecBufferDesc Message; + SECURITY_STATUS status; + + Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ + Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */ + + Buffers[0].cbBuffer = 16; + Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer); + CopyMemory(Buffers[0].pvBuffer, credssp->authInfo.pvBuffer, Buffers[0].cbBuffer); + + Buffers[1].cbBuffer = credssp->authInfo.cbBuffer - Buffers[0].cbBuffer; + Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer); + p = (BYTE*) credssp->authInfo.pvBuffer; + CopyMemory(Buffers[1].pvBuffer, &p[Buffers[0].cbBuffer], Buffers[1].cbBuffer); + + Message.cBuffers = 2; + Message.ulVersion = SECBUFFER_VERSION; + Message.pBuffers = (PSecBuffer) &Buffers; + + sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer); + + status = credssp->table->DecryptMessage(&credssp->context, &Message, 1, 0); + + freerdp_hexdump(Buffers[0].pvBuffer, Buffers[0].cbBuffer); + freerdp_hexdump(Buffers[1].pvBuffer, Buffers[1].cbBuffer); + + if (status != SEC_E_OK) + return status; + + free(Buffers[0].pvBuffer); + free(Buffers[1].pvBuffer); + + return SEC_E_OK; +} + int credssp_skip_ts_password_creds(rdpCredssp* credssp) { int length; diff --git a/winpr/sspi/NTLM/ntlm.c b/winpr/sspi/NTLM/ntlm.c index 61154239d..3904e5a02 100644 --- a/winpr/sspi/NTLM/ntlm.c +++ b/winpr/sspi/NTLM/ntlm.c @@ -564,7 +564,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, /* Copy original data buffer */ length = data_buffer->cbBuffer; data = malloc(length); - memcpy(data, data_buffer->pvBuffer, length); + CopyMemory(data, data_buffer->pvBuffer, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); @@ -599,9 +599,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, signature = (BYTE*) signature_buffer->pvBuffer; /* Concatenate version, ciphertext and sequence number to build signature */ - memcpy(signature, (void*) &version, 4); - memcpy(&signature[4], (void*) checksum, 8); - memcpy(&signature[12], (void*) &(MessageSeqNo), 4); + CopyMemory(signature, (void*) &version, 4); + CopyMemory(&signature[4], (void*) checksum, 8); + CopyMemory(&signature[12], (void*) &(MessageSeqNo), 4); context->SendSeqNum++; #ifdef WITH_DEBUG_NTLM @@ -646,10 +646,14 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD /* Copy original data buffer */ length = data_buffer->cbBuffer; data = malloc(length); - memcpy(data, data_buffer->pvBuffer, length); + CopyMemory(data, data_buffer->pvBuffer, length); - /* Decrypt message using with RC4 */ - crypto_rc4(context->RecvRc4Seal, length, data, data_buffer->pvBuffer); + /* Decrypt message using with RC4, result overwrites original buffer */ + + if (context->confidentiality) + crypto_rc4(context->RecvRc4Seal, length, data, data_buffer->pvBuffer); + else + CopyMemory(data_buffer->pvBuffer, data, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); @@ -675,15 +679,21 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD crypto_rc4(context->RecvRc4Seal, 8, digest, checksum); /* Concatenate version, ciphertext and sequence number to build signature */ - memcpy(expected_signature, (void*) &version, 4); - memcpy(&expected_signature[4], (void*) checksum, 8); - memcpy(&expected_signature[12], (void*) &(MessageSeqNo), 4); + CopyMemory(expected_signature, (void*) &version, 4); + CopyMemory(&expected_signature[4], (void*) checksum, 8); + CopyMemory(&expected_signature[12], (void*) &(MessageSeqNo), 4); context->RecvSeqNum++; if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0) { /* signature verification failed! */ printf("signature verification failed, something nasty is going on!\n"); + + printf("Expected Signature:\n"); + freerdp_hexdump(expected_signature, 16); + printf("Actual Signature:\n"); + freerdp_hexdump(signature_buffer->pvBuffer, 16); + return SEC_E_MESSAGE_ALTERED; } diff --git a/winpr/sspi/NTLM/ntlm_compute.c b/winpr/sspi/NTLM/ntlm_compute.c index 8657e3923..8db165186 100644 --- a/winpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/sspi/NTLM/ntlm_compute.c @@ -213,6 +213,11 @@ static void ascii_hex_string_to_binary(char* str, unsigned char* hex) } } +/* + * username // password + * username:661e58eb6743798326f388fc5edb0b3a + */ + void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) { FILE* fp; @@ -270,9 +275,8 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) { if (memcmp(User, context->identity.User, UserLength) == 0) { - printf("%s:%s\n", db_user, db_hash); ascii_hex_string_to_binary(db_hash, db_hash_bin); - memcpy(hash, db_hash_bin, 16); + CopyMemory(hash, db_hash_bin, 16); } } }