libwinpr-sspi: store NTLM hashes in SAM, generate NTLMv2 hashes on the fly

This commit is contained in:
Marc-André Moreau 2012-07-22 23:23:23 -04:00
parent ed6c83b76d
commit 6155e3718f
5 changed files with 100 additions and 37 deletions

View File

@ -34,12 +34,19 @@ WINPR_API BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User,
WINPR_API BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, WINPR_API BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User,
UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash); UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash);
WINPR_API BYTE* NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength,
LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash);
WINPR_API BYTE* NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength,
LPSTR Domain, UINT32 DomainLength, BYTE* NtHash);
#ifdef UNICODE #ifdef UNICODE
#define NTOWFv1 NTOWFv1W #define NTOWFv1 NTOWFv1W
#define NTOWFv2 NTOWFv2W #define NTOWFv2 NTOWFv2W
#define NTOWFv2FromHash NTOWFv2FromHashW
#else #else
#define NTOWFv1 NTOWFv1A #define NTOWFv1 NTOWFv1A
#define NTOWFv2 NTOWFv2W #define NTOWFv2 NTOWFv2A
#define NTOWFv2FromHash NTOWFv2FromHashA
#endif #endif
#endif /* WINPR_UTILS_NTLM_H */ #endif /* WINPR_UTILS_NTLM_H */

View File

@ -233,16 +233,36 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
if (entry != NULL) if (entry != NULL)
{ {
CopyMemory(hash, entry->NtHash, 16); NTOWFv2FromHashW(entry->NtHash,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
(BYTE*) hash);
SamFreeEntry(sam, entry);
SamClose(sam);
return;
}
entry = SamLookupUserW(sam,
(LPWSTR) context->identity.User, context->identity.UserLength * 2, NULL, 0);
if (entry != NULL)
{
NTOWFv2FromHashW(entry->NtHash,
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
(BYTE*) hash);
SamFreeEntry(sam, entry);
SamClose(sam);
return;
} }
else else
{ {
printf("Error: Could not find user in SAM database\n"); printf("Error: Could not find user in SAM database\n");
} }
SamFreeEntry(sam, entry);
SamClose(sam);
} }
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)

View File

@ -48,7 +48,6 @@ int main(int argc, char* argv[])
{ {
int index = 1; int index = 1;
BYTE NtHash[16]; BYTE NtHash[16];
BOOL sam_entry = 0;
char* User = NULL; char* User = NULL;
UINT32 UserLength; UINT32 UserLength;
char* Domain = NULL; char* Domain = NULL;
@ -100,10 +99,6 @@ int main(int argc, char* argv[])
printf("Usage: winpr-hash -u <username> -p <password> [-d <domain>]\n"); printf("Usage: winpr-hash -u <username> -p <password> [-d <domain>]\n");
exit(1); exit(1);
} }
else if (strcmp("-s", argv[index]) == 0)
{
sam_entry = 1;
}
index++; index++;
} }
@ -118,29 +113,22 @@ int main(int argc, char* argv[])
PasswordLength = strlen(Password); PasswordLength = strlen(Password);
DomainLength = (Domain) ? strlen(Domain) : 0; DomainLength = (Domain) ? strlen(Domain) : 0;
NTOWFv2A(Password, PasswordLength, User, UserLength, Domain, DomainLength, NtHash); NTOWFv1A(Password, PasswordLength, NtHash);
if (sam_entry) printf("%s:", User);
{
printf("%s:", User);
if (DomainLength > 0)
printf("%s:", Domain);
else
printf(":");
if (DomainLength > 0)
printf("%s:", Domain);
else
printf(":"); printf(":");
for (index = 0; index < 16; index++) printf(":");
printf("%02x", NtHash[index]);
printf("\n"); for (index = 0; index < 16; index++)
} printf("%02x", NtHash[index]);
else
{ printf(":::");
for (index = 0; index < 16; index++) printf("\n");
printf("%02x", NtHash[index]);
printf("\n");
}
return 0; return 0;
} }

View File

@ -61,7 +61,7 @@ BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash)
PasswordW = (LPWSTR) malloc(PasswordLength * 2); PasswordW = (LPWSTR) malloc(PasswordLength * 2);
MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength); MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength);
NtHash = NTOWFv1W(PasswordW, PasswordLength, NtHash); NtHash = NTOWFv1W(PasswordW, PasswordLength * 2, NtHash);
free(PasswordW); free(PasswordW);
@ -129,3 +129,49 @@ BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User,
return NtHash; return NtHash;
} }
BYTE* NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash)
{
BYTE* buffer;
if (!User)
return NULL;
if (!NtHash)
NtHash = (BYTE*) malloc(16);
buffer = (BYTE*) malloc(UserLength + DomainLength);
/* Concatenate(UpperCase(User), Domain) */
CopyMemory(buffer, User, UserLength);
CharUpperBuffW((LPWSTR) buffer, UserLength / 2);
CopyMemory(&buffer[UserLength], Domain, DomainLength);
/* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */
HMAC(EVP_md5(), (void*) NtHashV1, 16, buffer, UserLength + DomainLength, (void*) NtHash, NULL);
free(buffer);
return NtHash;
}
BYTE* NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash)
{
LPWSTR UserW = NULL;
LPWSTR DomainW = NULL;
LPWSTR PasswordW = NULL;
UserW = (LPWSTR) malloc(UserLength * 2);
DomainW = (LPWSTR) malloc(DomainLength * 2);
MultiByteToWideChar(CP_ACP, 0, User, UserLength, UserW, UserLength);
MultiByteToWideChar(CP_ACP, 0, Domain, DomainLength, DomainW, DomainLength);
NtHash = NTOWFv2FromHashW(NtHashV1, UserW, UserLength * 2, DomainW, DomainLength * 2, NtHash);
free(UserW);
free(DomainW);
free(PasswordW);
return NtHash;
}

View File

@ -112,7 +112,7 @@ void HexStrToBin(char* str, BYTE* bin, int length)
WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry) WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
{ {
char* p[5]; char* p[7];
int LmHashLength; int LmHashLength;
int NtHashLength; int NtHashLength;
@ -120,13 +120,15 @@ WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
p[1] = strchr(p[0], ':') + 1; p[1] = strchr(p[0], ':') + 1;
p[2] = strchr(p[1], ':') + 1; p[2] = strchr(p[1], ':') + 1;
p[3] = strchr(p[2], ':') + 1; p[3] = strchr(p[2], ':') + 1;
p[4] = p[0] + strlen(p[0]); p[4] = strchr(p[3], ':') + 1;
p[5] = strchr(p[4], ':') + 1;
p[6] = p[0] + strlen(p[0]);
entry->UserLength = p[1] - p[0] - 1; entry->UserLength = p[1] - p[0] - 1;
entry->DomainLength = p[2] - p[1] - 1; entry->DomainLength = p[2] - p[1] - 1;
LmHashLength = p[3] - p[2] - 1; LmHashLength = p[3] - p[2] - 1;
NtHashLength = p[4] - p[3]; NtHashLength = p[4] - p[3] - 1;
entry->User = (LPSTR) malloc(entry->UserLength + 1); entry->User = (LPSTR) malloc(entry->UserLength + 1);
memcpy(entry->User, p[0], entry->UserLength); memcpy(entry->User, p[0], entry->UserLength);