libwinpr-sspi: fix server-side NTLM signing and sealing
This commit is contained in:
parent
d57e879d7c
commit
2ff8a103d6
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user