freerdp: implement restricted admin mode pass-the-hash option
This commit is contained in:
parent
a3d0e271b5
commit
b8a1f7d6c0
@ -52,6 +52,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "kbd-fn-key", COMMAND_LINE_VALUE_REQUIRED, "<function key count>", NULL, NULL, -1, NULL, "Keyboard function key count" },
|
||||
{ "admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "console", "Admin (or console) session" },
|
||||
{ "restricted-admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "restrictedAdmin", "Restricted admin mode" },
|
||||
{ "pth", COMMAND_LINE_VALUE_REQUIRED, "<password hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" },
|
||||
{ "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" },
|
||||
{ "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" },
|
||||
{ "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" },
|
||||
@ -1237,6 +1238,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
||||
settings->ConsoleSession = TRUE;
|
||||
settings->RestrictedAdminModeRequired = TRUE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "pth")
|
||||
{
|
||||
settings->ConsoleSession = TRUE;
|
||||
settings->RestrictedAdminModeRequired = TRUE;
|
||||
settings->PasswordHash = _strdup(arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "kbd")
|
||||
{
|
||||
int id;
|
||||
|
@ -476,6 +476,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
|
||||
#define FreeRDP_Username 21
|
||||
#define FreeRDP_Password 22
|
||||
#define FreeRDP_Domain 23
|
||||
#define FreeRDP_PasswordHash 24
|
||||
#define FreeRDP_RdpVersion 128
|
||||
#define FreeRDP_DesktopWidth 129
|
||||
#define FreeRDP_DesktopHeight 130
|
||||
@ -760,7 +761,8 @@ struct rdp_settings
|
||||
ALIGN64 char* Username; /* 21 */
|
||||
ALIGN64 char* Password; /* 22 */
|
||||
ALIGN64 char* Domain; /* 23 */
|
||||
UINT64 padding0064[64 - 24]; /* 24 */
|
||||
ALIGN64 char* PasswordHash; /* 24 */
|
||||
UINT64 padding0064[64 - 25]; /* 25 */
|
||||
UINT64 padding0128[128 - 64]; /* 64 */
|
||||
|
||||
/**
|
||||
|
@ -2096,6 +2096,10 @@ char* freerdp_get_param_string(rdpSettings* settings, int id)
|
||||
return settings->Domain;
|
||||
break;
|
||||
|
||||
case FreeRDP_PasswordHash:
|
||||
return settings->PasswordHash;
|
||||
break;
|
||||
|
||||
case FreeRDP_ClientHostname:
|
||||
return settings->ClientHostname;
|
||||
break;
|
||||
@ -2264,6 +2268,11 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
|
||||
settings->Domain = _strdup(param);
|
||||
break;
|
||||
|
||||
case FreeRDP_PasswordHash:
|
||||
free(settings->PasswordHash);
|
||||
settings->PasswordHash = _strdup(param);
|
||||
break;
|
||||
|
||||
case FreeRDP_ClientHostname:
|
||||
free(settings->ClientHostname);
|
||||
settings->ClientHostname = _strdup(param);
|
||||
|
@ -113,20 +113,39 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
{
|
||||
char* spn;
|
||||
int length;
|
||||
BOOL PromptPassword;
|
||||
rdpTls* tls = NULL;
|
||||
freerdp* instance;
|
||||
rdpSettings* settings;
|
||||
|
||||
PromptPassword = FALSE;
|
||||
settings = credssp->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
|
||||
if ((settings->Password == NULL ) || (settings->Username == NULL)
|
||||
if ((!settings->Password) || (!settings->Username)
|
||||
|| (!strlen(settings->Password)) || (!strlen(settings->Username)))
|
||||
{
|
||||
PromptPassword = TRUE;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (PromptPassword)
|
||||
{
|
||||
if (settings->RestrictedAdminModeRequired)
|
||||
{
|
||||
if ((settings->PasswordHash) && (strlen(settings->PasswordHash) > 0))
|
||||
PromptPassword = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (PromptPassword)
|
||||
{
|
||||
if (instance->Authenticate)
|
||||
{
|
||||
BOOL proceed = instance->Authenticate(instance,
|
||||
&settings->Username, &settings->Password, &settings->Domain);
|
||||
|
||||
if (!proceed)
|
||||
return 0;
|
||||
}
|
||||
@ -134,6 +153,33 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
|
||||
sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password);
|
||||
|
||||
#ifndef _WIN32
|
||||
{
|
||||
SEC_WINNT_AUTH_IDENTITY* identity = &(credssp->identity);
|
||||
|
||||
if (settings->RestrictedAdminModeRequired)
|
||||
{
|
||||
if (settings->PasswordHash)
|
||||
{
|
||||
if (strlen(settings->PasswordHash) == 32)
|
||||
{
|
||||
if (identity->Password)
|
||||
free(identity->Password);
|
||||
|
||||
identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0,
|
||||
settings->PasswordHash, -1, &identity->Password, 0) - 1;
|
||||
|
||||
/**
|
||||
* Multiply password hash length by 64 to obtain a length exceeding
|
||||
* the maximum (256) and use it this for hash identification in WinPR.
|
||||
*/
|
||||
identity->PasswordLength = 32 * 64; /* 2048 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DEBUG_NLA
|
||||
_tprintf(_T("User: %s Domain: %s Password: %s\n"),
|
||||
(char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password);
|
||||
|
@ -445,6 +445,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
|
||||
_settings->Username = _strdup(settings->Username); /* 21 */
|
||||
_settings->Password = _strdup(settings->Password); /* 22 */
|
||||
_settings->Domain = _strdup(settings->Domain); /* 23 */
|
||||
_settings->PasswordHash = _strdup(settings->PasswordHash); /* 24 */
|
||||
//_settings->ClientHostname = _strdup(settings->ClientHostname); /* 134 */
|
||||
//_settings->ClientProductId = _strdup(settings->ClientProductId); /* 135 */
|
||||
_settings->AlternateShell = _strdup(settings->AlternateShell); /* 640 */
|
||||
@ -780,6 +781,7 @@ void freerdp_settings_free(rdpSettings* settings)
|
||||
free(settings->Username);
|
||||
free(settings->Password);
|
||||
free(settings->Domain);
|
||||
free(settings->PasswordHash);
|
||||
free(settings->AlternateShell);
|
||||
free(settings->ShellWorkingDirectory);
|
||||
free(settings->ComputerName);
|
||||
|
@ -282,9 +282,43 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
SamClose(sam);
|
||||
}
|
||||
|
||||
void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
int i, hn, ln;
|
||||
char* PasswordHash = NULL;
|
||||
UINT32 PasswordHashLength = 0;
|
||||
|
||||
/* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */
|
||||
|
||||
PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
ConvertFromUnicode(CP_UTF8, 0, context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
CharUpperBuffA(PasswordHash, PasswordHashLength);
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
{
|
||||
hn = PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0';
|
||||
ln = PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 : PasswordHash[i + 1] - '0';
|
||||
hash[i / 2] = (hn << 4) | ln;
|
||||
}
|
||||
|
||||
free(PasswordHash);
|
||||
}
|
||||
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
{
|
||||
if (context->identity.PasswordLength > 0)
|
||||
if (context->identity.PasswordLength > 256)
|
||||
{
|
||||
BYTE PasswordHash[16];
|
||||
|
||||
/* Special case for WinPR: password hash */
|
||||
ntlm_convert_password_hash(context, PasswordHash);
|
||||
|
||||
NTOWFv2FromHashW(PasswordHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
}
|
||||
else if (context->identity.PasswordLength > 0)
|
||||
{
|
||||
NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength * 2,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
|
@ -192,11 +192,10 @@ CREDENTIALS* sspi_CredentialsNew()
|
||||
CREDENTIALS* credentials;
|
||||
|
||||
credentials = (CREDENTIALS*) malloc(sizeof(CREDENTIALS));
|
||||
ZeroMemory(credentials, sizeof(CREDENTIALS));
|
||||
|
||||
if (credentials != NULL)
|
||||
if (credentials)
|
||||
{
|
||||
|
||||
ZeroMemory(credentials, sizeof(CREDENTIALS));
|
||||
}
|
||||
|
||||
return credentials;
|
||||
@ -319,7 +318,7 @@ void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* d
|
||||
identity->DomainLength = 0;
|
||||
}
|
||||
|
||||
if (password != NULL)
|
||||
if (password)
|
||||
{
|
||||
identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0, password, -1, &identity->Password, 0) - 1;
|
||||
}
|
||||
@ -366,12 +365,17 @@ void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDE
|
||||
|
||||
identity->PasswordLength = srcIdentity->PasswordLength;
|
||||
|
||||
if (identity->PasswordLength > 256)
|
||||
identity->PasswordLength /= SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
|
||||
if (identity->PasswordLength > 0)
|
||||
{
|
||||
identity->Password = (UINT16*) malloc((identity->PasswordLength + 1) * sizeof(WCHAR));
|
||||
CopyMemory(identity->Password, srcIdentity->Password, identity->PasswordLength * sizeof(WCHAR));
|
||||
identity->Password[identity->PasswordLength] = 0;
|
||||
}
|
||||
|
||||
identity->PasswordLength = srcIdentity->PasswordLength;
|
||||
}
|
||||
|
||||
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType)
|
||||
|
@ -24,8 +24,13 @@
|
||||
|
||||
#define SCHANNEL_CB_MAX_TOKEN 0x00006000
|
||||
|
||||
#define SSPI_CREDENTIALS_PASSWORD_HASH 0x00000001
|
||||
|
||||
#define SSPI_CREDENTIALS_HASH_LENGTH_FACTOR 64
|
||||
|
||||
struct _CREDENTIALS
|
||||
{
|
||||
DWORD flags;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _CREDENTIALS CREDENTIALS;
|
||||
|
Loading…
Reference in New Issue
Block a user