libwinpr-sspi: store NTLM hashes in SAM, generate NTLMv2 hashes on the fly
This commit is contained in:
parent
ed6c83b76d
commit
6155e3718f
@ -34,12 +34,19 @@ WINPR_API BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User,
|
||||
WINPR_API BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User,
|
||||
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
|
||||
#define NTOWFv1 NTOWFv1W
|
||||
#define NTOWFv2 NTOWFv2W
|
||||
#define NTOWFv1 NTOWFv1W
|
||||
#define NTOWFv2 NTOWFv2W
|
||||
#define NTOWFv2FromHash NTOWFv2FromHashW
|
||||
#else
|
||||
#define NTOWFv1 NTOWFv1A
|
||||
#define NTOWFv2 NTOWFv2W
|
||||
#define NTOWFv1 NTOWFv1A
|
||||
#define NTOWFv2 NTOWFv2A
|
||||
#define NTOWFv2FromHash NTOWFv2FromHashA
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_UTILS_NTLM_H */
|
||||
|
@ -233,16 +233,36 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
|
@ -48,7 +48,6 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
int index = 1;
|
||||
BYTE NtHash[16];
|
||||
BOOL sam_entry = 0;
|
||||
char* User = NULL;
|
||||
UINT32 UserLength;
|
||||
char* Domain = NULL;
|
||||
@ -100,10 +99,6 @@ int main(int argc, char* argv[])
|
||||
printf("Usage: winpr-hash -u <username> -p <password> [-d <domain>]\n");
|
||||
exit(1);
|
||||
}
|
||||
else if (strcmp("-s", argv[index]) == 0)
|
||||
{
|
||||
sam_entry = 1;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
@ -118,29 +113,22 @@ int main(int argc, char* argv[])
|
||||
PasswordLength = strlen(Password);
|
||||
DomainLength = (Domain) ? strlen(Domain) : 0;
|
||||
|
||||
NTOWFv2A(Password, PasswordLength, User, UserLength, Domain, DomainLength, NtHash);
|
||||
NTOWFv1A(Password, PasswordLength, NtHash);
|
||||
|
||||
if (sam_entry)
|
||||
{
|
||||
printf("%s:", User);
|
||||
|
||||
if (DomainLength > 0)
|
||||
printf("%s:", Domain);
|
||||
else
|
||||
printf(":");
|
||||
printf("%s:", User);
|
||||
|
||||
if (DomainLength > 0)
|
||||
printf("%s:", Domain);
|
||||
else
|
||||
printf(":");
|
||||
|
||||
for (index = 0; index < 16; index++)
|
||||
printf("%02x", NtHash[index]);
|
||||
printf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (index = 0; index < 16; index++)
|
||||
printf("%02x", NtHash[index]);
|
||||
printf("\n");
|
||||
}
|
||||
printf(":");
|
||||
|
||||
for (index = 0; index < 16; index++)
|
||||
printf("%02x", NtHash[index]);
|
||||
|
||||
printf(":::");
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash)
|
||||
PasswordW = (LPWSTR) malloc(PasswordLength * 2);
|
||||
MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength);
|
||||
|
||||
NtHash = NTOWFv1W(PasswordW, PasswordLength, NtHash);
|
||||
NtHash = NTOWFv1W(PasswordW, PasswordLength * 2, NtHash);
|
||||
|
||||
free(PasswordW);
|
||||
|
||||
@ -129,3 +129,49 @@ BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User,
|
||||
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;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ void HexStrToBin(char* str, BYTE* bin, int length)
|
||||
|
||||
WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
|
||||
{
|
||||
char* p[5];
|
||||
char* p[7];
|
||||
int LmHashLength;
|
||||
int NtHashLength;
|
||||
|
||||
@ -120,13 +120,15 @@ WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
|
||||
p[1] = strchr(p[0], ':') + 1;
|
||||
p[2] = strchr(p[1], ':') + 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->DomainLength = p[2] - p[1] - 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);
|
||||
memcpy(entry->User, p[0], entry->UserLength);
|
||||
|
Loading…
Reference in New Issue
Block a user