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,
|
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 */
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user