Merge pull request #1913 from awakecoding/master
NTLM SSPI Module Improvements
This commit is contained in:
commit
ad1369843c
@ -814,6 +814,38 @@ int freerdp_parse_username(char* username, char** user, char** domain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_parse_hostname(char* hostname, char** host, int* port)
|
||||
{
|
||||
char* p;
|
||||
int length;
|
||||
|
||||
p = strrchr(hostname, ':');
|
||||
|
||||
if (p)
|
||||
{
|
||||
length = (p - hostname);
|
||||
*host = (char*) malloc(length + 1);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
CopyMemory(*host, hostname, length);
|
||||
(*host)[length] = '\0';
|
||||
*port = atoi(p + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*host = _strdup(hostname);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
*port = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_set_connection_type(rdpSettings* settings, int type)
|
||||
{
|
||||
settings->ConnectionType = type;
|
||||
|
@ -767,10 +767,23 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
free(domain);
|
||||
}
|
||||
|
||||
if (~((size_t) file->FullAddress))
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->FullAddress, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->ServerPort)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->ServerPort);
|
||||
if (~((size_t) file->FullAddress))
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->FullAddress);
|
||||
|
||||
if (~file->DesktopWidth)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, file->DesktopWidth);
|
||||
@ -867,7 +880,19 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
freerdp_set_param_bool(settings, FreeRDP_CompressionEnabled, file->Compression);
|
||||
|
||||
if (~((size_t) file->GatewayHostname))
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, file->GatewayHostname);
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->GatewayHostname, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_GatewayPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->GatewayUsageMethod)
|
||||
freerdp_set_gateway_usage_method(settings, file->GatewayUsageMethod);
|
||||
|
@ -35,6 +35,7 @@ FREERDP_API int freerdp_client_print_version(void);
|
||||
FREERDP_API int freerdp_client_print_command_line_help(int argc, char** argv);
|
||||
|
||||
FREERDP_API int freerdp_parse_username(char* username, char** user, char** domain);
|
||||
FREERDP_API int freerdp_parse_hostname(char* hostname, char** host, int* port);
|
||||
FREERDP_API int freerdp_set_connection_type(rdpSettings* settings, int type);
|
||||
|
||||
FREERDP_API int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** params);
|
||||
|
@ -997,6 +997,10 @@ extern "C" {
|
||||
#define SECPKG_ATTR_AUTH_IDENTITY 1001
|
||||
#define SECPKG_ATTR_AUTH_PASSWORD 1002
|
||||
#define SECPKG_ATTR_AUTH_NTLM_HASH 1003
|
||||
#define SECPKG_ATTR_AUTH_NTLM_MESSAGE 1100
|
||||
#define SECPKG_ATTR_AUTH_NTLM_TIMESTAMP 1101
|
||||
#define SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE 1102
|
||||
#define SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE 1103
|
||||
|
||||
struct _SecPkgContext_AuthIdentity
|
||||
{
|
||||
@ -1013,10 +1017,38 @@ typedef struct _SecPkgContext_AuthPassword SecPkgContext_AuthPassword;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmHash
|
||||
{
|
||||
int Version;
|
||||
BYTE NtlmHash[16];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmHash SecPkgContext_AuthNtlmHash;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmTimestamp
|
||||
{
|
||||
BYTE Timestamp[8];
|
||||
BOOL ChallengeOrResponse;
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmTimestamp SecPkgContext_AuthNtlmTimestamp;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmClientChallenge
|
||||
{
|
||||
BYTE ClientChallenge[8];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmClientChallenge SecPkgContext_AuthNtlmClientChallenge;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmServerChallenge
|
||||
{
|
||||
BYTE ServerChallenge[8];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmServerChallenge SecPkgContext_AuthNtlmServerChallenge;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmMessage
|
||||
{
|
||||
UINT32 type;
|
||||
UINT32 length;
|
||||
BYTE* buffer;
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmMessage SecPkgContext_AuthNtlmMessage;
|
||||
|
||||
#define SSPI_INTERFACE_WINPR 0x00000001
|
||||
#define SSPI_INTERFACE_NATIVE 0x00000002
|
||||
|
||||
|
@ -167,6 +167,8 @@ NTLM_CONTEXT* ntlm_ContextNew()
|
||||
context->SendVersionInfo = TRUE;
|
||||
context->SendSingleHostData = FALSE;
|
||||
context->SendWorkstationName = TRUE;
|
||||
context->NegotiateKeyExchange = TRUE;
|
||||
context->UseSamFileDatabase = TRUE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
@ -674,6 +676,8 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, UL
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*) pBuffer;
|
||||
|
||||
context->UseSamFileDatabase = FALSE;
|
||||
|
||||
credentials = context->credentials;
|
||||
ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
|
||||
|
||||
@ -723,7 +727,74 @@ SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULON
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
if (AuthNtlmHash->Version == 1)
|
||||
CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
|
||||
else if (AuthNtlmHash->Version == 2)
|
||||
CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MESSAGE)
|
||||
{
|
||||
SecPkgContext_AuthNtlmMessage* AuthNtlmMessage = (SecPkgContext_AuthNtlmMessage*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmMessage))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
if (AuthNtlmMessage->type == 1)
|
||||
{
|
||||
sspi_SecBufferFree(&context->NegotiateMessage);
|
||||
sspi_SecBufferAlloc(&context->NegotiateMessage, AuthNtlmMessage->length);
|
||||
CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer, AuthNtlmMessage->length);
|
||||
}
|
||||
else if (AuthNtlmMessage->type == 2)
|
||||
{
|
||||
sspi_SecBufferFree(&context->ChallengeMessage);
|
||||
sspi_SecBufferAlloc(&context->ChallengeMessage, AuthNtlmMessage->length);
|
||||
CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer, AuthNtlmMessage->length);
|
||||
}
|
||||
else if (AuthNtlmMessage->type == 3)
|
||||
{
|
||||
sspi_SecBufferFree(&context->AuthenticateMessage);
|
||||
sspi_SecBufferAlloc(&context->AuthenticateMessage, AuthNtlmMessage->length);
|
||||
CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer, AuthNtlmMessage->length);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_TIMESTAMP)
|
||||
{
|
||||
SecPkgContext_AuthNtlmTimestamp* AuthNtlmTimestamp = (SecPkgContext_AuthNtlmTimestamp*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmTimestamp))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
if (AuthNtlmTimestamp->ChallengeOrResponse)
|
||||
CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
|
||||
else
|
||||
CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE)
|
||||
{
|
||||
SecPkgContext_AuthNtlmClientChallenge* AuthNtlmClientChallenge = (SecPkgContext_AuthNtlmClientChallenge*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmClientChallenge))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE)
|
||||
{
|
||||
SecPkgContext_AuthNtlmServerChallenge* AuthNtlmServerChallenge = (SecPkgContext_AuthNtlmServerChallenge*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmServerChallenge))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
@ -241,6 +241,7 @@ struct _NTLM_CONTEXT
|
||||
BYTE* SendSealingKey;
|
||||
BYTE* RecvSealingKey;
|
||||
UINT32 NegotiateFlags;
|
||||
BOOL UseSamFileDatabase;
|
||||
int LmCompatibilityLevel;
|
||||
int SuppressExtendedProtection;
|
||||
BOOL SendWorkstationName;
|
||||
@ -251,6 +252,7 @@ struct _NTLM_CONTEXT
|
||||
BYTE ChannelBindingsHash[16];
|
||||
SecPkgContext_Bindings Bindings;
|
||||
BOOL SendSingleHostData;
|
||||
BOOL NegotiateKeyExchange;
|
||||
NTLM_SINGLE_HOST_DATA SingleHostData;
|
||||
NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE;
|
||||
NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE;
|
||||
|
@ -39,7 +39,7 @@ static const char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client si
|
||||
static const char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
static const BYTE NTLM_NULL_HASH[16] =
|
||||
static const BYTE NTLM_NULL_BUFFER[16] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
/**
|
||||
@ -193,11 +193,7 @@ void ntlm_current_time(BYTE* timestamp)
|
||||
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE ZeroTimestamp[8];
|
||||
|
||||
ZeroMemory(ZeroTimestamp, 8);
|
||||
|
||||
if (memcmp(ZeroTimestamp, context->ChallengeTimestamp, 8) != 0)
|
||||
if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0)
|
||||
CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8);
|
||||
else
|
||||
ntlm_current_time(context->Timestamp);
|
||||
@ -303,7 +299,10 @@ int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
if (memcmp(context->NtlmHash, NTLM_NULL_HASH, 16) != 0)
|
||||
if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
return 1;
|
||||
|
||||
if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
{
|
||||
NTOWFv2FromHashW(context->NtlmHash,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
@ -328,7 +327,7 @@ int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash);
|
||||
}
|
||||
else
|
||||
else if (context->UseSamFileDatabase)
|
||||
{
|
||||
ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
@ -388,7 +387,9 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
SecBuffer ntlm_v2_temp;
|
||||
SecBuffer ntlm_v2_temp_chal;
|
||||
PSecBuffer TargetInfo;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
credentials = context->credentials;
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
@ -403,16 +404,16 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
return -1;
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "Password (length = %d)\n", context->identity.PasswordLength * 2);
|
||||
winpr_HexDump((BYTE*) context->identity.Password, context->identity.PasswordLength * 2);
|
||||
fprintf(stderr, "Password (length = %d)\n", credentials->identity.PasswordLength * 2);
|
||||
winpr_HexDump((BYTE*) credentials->identity.Password, credentials->identity.PasswordLength * 2);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "Username (length = %d)\n", context->identity.UserLength * 2);
|
||||
winpr_HexDump((BYTE*) context->identity.User, context->identity.UserLength * 2);
|
||||
fprintf(stderr, "Username (length = %d)\n", credentials->identity.UserLength * 2);
|
||||
winpr_HexDump((BYTE*) credentials->identity.User, credentials->identity.UserLength * 2);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "Domain (length = %d)\n", context->identity.DomainLength * 2);
|
||||
winpr_HexDump((BYTE*) context->identity.Domain, context->identity.DomainLength * 2);
|
||||
fprintf(stderr, "Domain (length = %d)\n", credentials->identity.DomainLength * 2);
|
||||
winpr_HexDump((BYTE*) credentials->identity.Domain, credentials->identity.DomainLength * 2);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "Workstation (length = %d)\n", context->Workstation.Length);
|
||||
@ -497,6 +498,8 @@ void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext)
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
/* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */
|
||||
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
RAND_bytes(context->ClientChallenge, 8);
|
||||
}
|
||||
|
||||
@ -507,6 +510,7 @@ void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
RAND_bytes(context->ServerChallenge, 8);
|
||||
}
|
||||
|
||||
@ -561,7 +565,18 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the KeyExchangeKey */
|
||||
|
||||
/**
|
||||
* if (NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
|
||||
* Set RandomSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
|
||||
* else
|
||||
* Set RandomSessionKey to KeyExchangeKey
|
||||
*/
|
||||
|
||||
if (context->NegotiateKeyExchange)
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey, context->RandomSessionKey);
|
||||
else
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -713,17 +713,11 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
|
||||
Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
|
||||
|
||||
if (!(message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) &&
|
||||
(message->DomainName.Len || message->DomainName.MaxLen))
|
||||
return SEC_E_INVALID_TOKEN; /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
|
||||
context->NegotiateKeyExchange = (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE;
|
||||
|
||||
if (!(message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) &&
|
||||
(message->Workstation.Len || message->Workstation.MaxLen))
|
||||
return SEC_E_INVALID_TOKEN; /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
|
||||
|
||||
if (!(message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) &&
|
||||
(message->EncryptedRandomSessionKey.Len || message->EncryptedRandomSessionKey.MaxLen))
|
||||
return SEC_E_INVALID_TOKEN; /* only set if NTLMSSP_NEGOTIATE_KEY_EXCH is set */
|
||||
if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
|
||||
(!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
|
||||
{
|
||||
@ -778,7 +772,13 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) < 0) /* EncryptedRandomSessionKey */
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (message->EncryptedRandomSessionKey.Len > 0)
|
||||
{
|
||||
if (message->EncryptedRandomSessionKey.Len != 16)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer, 16);
|
||||
}
|
||||
|
||||
length = Stream_GetPosition(s);
|
||||
|
||||
@ -816,7 +816,7 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
|
||||
ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
|
||||
ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
|
||||
|
||||
ntlm_print_av_pair_list(response.Challenge.AvPairs);
|
||||
ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs);
|
||||
|
||||
if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
|
||||
{
|
||||
|
@ -3,6 +3,58 @@
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 };
|
||||
|
||||
static BYTE TEST_NTLM_CLIENT_CHALLENGE[8] = { 0x20, 0xc0, 0x2b, 0x3d, 0xc0, 0x61, 0xa7, 0x73 };
|
||||
|
||||
static BYTE TEST_NTLM_SERVER_CHALLENGE[8] = { 0xa4, 0xf1, 0xba, 0xa6, 0x7c, 0xdc, 0x1a, 0x12 };
|
||||
|
||||
static BYTE TEST_NTLM_NEGOTIATE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f";
|
||||
|
||||
static BYTE TEST_NTLM_CHALLENGE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x38\x00\x00\x00\x07\x82\x88\xa2\xa4\xf1\xba\xa6\x7c\xdc\x1a\x12"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x66\x00\x66\x00\x38\x00\x00\x00"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f\x02\x00\x0e\x00\x4e\x00\x45\x00"
|
||||
"\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00"
|
||||
"\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00"
|
||||
"\x6c\x00\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00"
|
||||
"\x2e\x00\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00"
|
||||
"\x6e\x00\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00"
|
||||
"\x08\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x00\x00\x00\x00";
|
||||
|
||||
static BYTE TEST_NTLM_AUTHENTICATE[] =
|
||||
"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00"
|
||||
"\x82\x00\x00\x00\x08\x01\x08\x01\x9a\x00\x00\x00\x0c\x00\x0c\x00"
|
||||
"\x58\x00\x00\x00\x10\x00\x10\x00\x64\x00\x00\x00\x0e\x00\x0e\x00"
|
||||
"\x74\x00\x00\x00\x00\x00\x00\x00\xa2\x01\x00\x00\x05\x82\x88\xa2"
|
||||
"\x06\x03\x80\x25\x00\x00\x00\x0f\x12\xe5\x5a\xf5\x80\xee\x3f\x29"
|
||||
"\xe1\xde\x90\x4d\x73\x77\x06\x25\x44\x00\x6f\x00\x6d\x00\x61\x00"
|
||||
"\x69\x00\x6e\x00\x55\x00\x73\x00\x65\x00\x72\x00\x6e\x00\x61\x00"
|
||||
"\x6d\x00\x65\x00\x4e\x00\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00"
|
||||
"\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x62\x14\x68\xc8\x98\x12"
|
||||
"\xe7\x39\xd8\x76\x1b\xe9\xf7\x54\xb5\xe3\x01\x01\x00\x00\x00\x00"
|
||||
"\x00\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x20\xc0\x2b\x3d\xc0\x61"
|
||||
"\xa7\x73\x00\x00\x00\x00\x02\x00\x0e\x00\x4e\x00\x45\x00\x57\x00"
|
||||
"\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00\x45\x00"
|
||||
"\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00\x6c\x00"
|
||||
"\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00\x2e\x00"
|
||||
"\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00\x6e\x00"
|
||||
"\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00\x08\x00"
|
||||
"\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x06\x00\x04\x00\x02\x00\x00\x00"
|
||||
"\x08\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
"\x00\x20\x00\x00\x1e\x10\xf5\x2c\x54\x2f\x2e\x77\x1c\x13\xbf\xc3"
|
||||
"\x3f\xe1\x7b\x28\x7e\x0b\x93\x5a\x39\xd2\xce\x12\xd7\xbd\x8c\x4e"
|
||||
"\x2b\xb5\x0b\xf5\x0a\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x1a\x00\x48\x00\x54\x00"
|
||||
"\x54\x00\x50\x00\x2f\x00\x72\x00\x77\x00\x2e\x00\x6c\x00\x6f\x00"
|
||||
"\x63\x00\x61\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00";
|
||||
|
||||
#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
|
||||
|
||||
static const char* TEST_NTLM_USER = "Username";
|
||||
@ -14,6 +66,11 @@ static const char* TEST_NTLM_PASSWORD = "P4ss123!";
|
||||
static const BYTE TEST_NTLM_HASH[16] =
|
||||
{ 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82, 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
|
||||
|
||||
//static const char* TEST_NTLM_HASH_V2_STRING = "4c7f706f7dde05a9d1a0f4e7ffe3bfb8";
|
||||
|
||||
static const BYTE TEST_NTLM_V2_HASH[16] =
|
||||
{ 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9, 0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 };
|
||||
|
||||
//#define NTLM_PACKAGE_NAME NEGOSSP_NAME
|
||||
#define NTLM_PACKAGE_NAME NTLMSP_NAME
|
||||
|
||||
@ -251,6 +308,7 @@ struct _TEST_NTLM_SERVER
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
BOOL UseNtlmV2Hash;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
@ -266,6 +324,8 @@ int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
ntlm->UseNtlmV2Hash = TRUE;
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
@ -370,7 +430,16 @@ int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (strcmp(AuthIdentity.User, TEST_NTLM_USER) == 0)
|
||||
{
|
||||
if (ntlm->UseNtlmV2Hash)
|
||||
{
|
||||
AuthNtlmHash.Version = 2;
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, TEST_NTLM_V2_HASH, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthNtlmHash.Version = 1;
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, TEST_NTLM_HASH, 16);
|
||||
}
|
||||
|
||||
status = ntlm->table->SetContextAttributes(&ntlm->context,
|
||||
SECPKG_ATTR_AUTH_NTLM_HASH, &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
@ -426,6 +495,7 @@ int TestNTLM(int argc, char* argv[])
|
||||
PSecBuffer pSecBuffer;
|
||||
TEST_NTLM_CLIENT* client;
|
||||
TEST_NTLM_SERVER* server;
|
||||
BOOL DynamicTest = TRUE;
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
@ -467,8 +537,40 @@ int TestNTLM(int argc, char* argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!DynamicTest)
|
||||
{
|
||||
SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp;
|
||||
SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge;
|
||||
SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge;
|
||||
|
||||
CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
|
||||
client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
|
||||
client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
|
||||
CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
|
||||
CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
|
||||
|
||||
client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE,
|
||||
&AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge));
|
||||
client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE,
|
||||
&AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge));
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
if (!DynamicTest)
|
||||
{
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_NEGOTIATE) -1;
|
||||
pSecBuffer->pvBuffer = (void*) malloc(pSecBuffer->cbBuffer);
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
|
||||
}
|
||||
|
||||
fprintf(stderr, "NTLM_NEGOTIATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
@ -490,8 +592,49 @@ int TestNTLM(int argc, char* argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!DynamicTest)
|
||||
{
|
||||
SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp;
|
||||
SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge;
|
||||
SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge;
|
||||
|
||||
CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
|
||||
client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
|
||||
AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
|
||||
client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
|
||||
&AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp));
|
||||
|
||||
CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
|
||||
CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
|
||||
|
||||
server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE,
|
||||
&AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge));
|
||||
server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE,
|
||||
&AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge));
|
||||
}
|
||||
|
||||
pSecBuffer = &(server->outputBuffer[0]);
|
||||
|
||||
if (!DynamicTest)
|
||||
{
|
||||
SecPkgContext_AuthNtlmMessage AuthNtlmMessage;
|
||||
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_CHALLENGE) -1;
|
||||
pSecBuffer->pvBuffer = (void*) malloc(pSecBuffer->cbBuffer);
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
|
||||
|
||||
AuthNtlmMessage.type = 2;
|
||||
AuthNtlmMessage.length = pSecBuffer->cbBuffer;
|
||||
AuthNtlmMessage.buffer = (BYTE*) pSecBuffer->pvBuffer;
|
||||
|
||||
server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE,
|
||||
&AuthNtlmMessage, sizeof(SecPkgContext_AuthNtlmMessage));
|
||||
}
|
||||
|
||||
fprintf(stderr, "NTLM_CHALLENGE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
@ -514,6 +657,12 @@ int TestNTLM(int argc, char* argv[])
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
if (!DynamicTest)
|
||||
{
|
||||
pSecBuffer->cbBuffer = sizeof(TEST_NTLM_AUTHENTICATE) -1;
|
||||
pSecBuffer->pvBuffer = (void*) malloc(pSecBuffer->cbBuffer);
|
||||
CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
|
||||
}
|
||||
|
||||
fprintf(stderr, "NTLM_AUTHENTICATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
@ -47,6 +47,8 @@
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int index = 1;
|
||||
int format = 0;
|
||||
int version = 1;
|
||||
BYTE NtHash[16];
|
||||
char* User = NULL;
|
||||
UINT32 UserLength;
|
||||
@ -93,10 +95,40 @@ int main(int argc, char* argv[])
|
||||
|
||||
Password = argv[index];
|
||||
}
|
||||
else if (strcmp("-v", argv[index]) == 0)
|
||||
{
|
||||
index++;
|
||||
|
||||
if (index == argc)
|
||||
{
|
||||
printf("missing version\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
version = atoi(argv[index]);
|
||||
|
||||
if ((version != 1) && (version != 2))
|
||||
version = 1;
|
||||
}
|
||||
else if (strcmp("-f", argv[index]) == 0)
|
||||
{
|
||||
index++;
|
||||
|
||||
if (index == argc)
|
||||
{
|
||||
printf("missing format\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strcmp("default", argv[index]) == 0)
|
||||
format = 0;
|
||||
else if (strcmp("sam", argv[index]) == 0)
|
||||
format = 1;
|
||||
}
|
||||
else if (strcmp("-h", argv[index]) == 0)
|
||||
{
|
||||
printf("winpr-hash: NTLM hashing tool\n");
|
||||
printf("Usage: winpr-hash -u <username> -p <password> [-d <domain>]\n");
|
||||
printf("Usage: winpr-hash -u <username> -p <password> [-d <domain>] -f <default,sam> -v <1,2>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -113,8 +145,29 @@ int main(int argc, char* argv[])
|
||||
PasswordLength = strlen(Password);
|
||||
DomainLength = (Domain) ? strlen(Domain) : 0;
|
||||
|
||||
NTOWFv1A(Password, PasswordLength, NtHash);
|
||||
if (version == 2)
|
||||
{
|
||||
if (!Domain)
|
||||
{
|
||||
printf("missing domain\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
NTOWFv2A(Password, PasswordLength, User, UserLength, Domain, DomainLength, NtHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
NTOWFv1A(Password, PasswordLength, NtHash);
|
||||
}
|
||||
|
||||
if (format == 0)
|
||||
{
|
||||
for (index = 0; index < 16; index++)
|
||||
printf("%02x", NtHash[index]);
|
||||
printf("\n");
|
||||
}
|
||||
else if (format == 1)
|
||||
{
|
||||
printf("%s:", User);
|
||||
|
||||
if (DomainLength > 0)
|
||||
@ -129,6 +182,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
printf(":::");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user