freerdp: implement restricted admin mode pass-the-hash option

This commit is contained in:
Marc-André Moreau 2013-11-06 10:02:58 -05:00
parent a3d0e271b5
commit b8a1f7d6c0
8 changed files with 116 additions and 7 deletions

View File

@ -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;

View File

@ -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 */
/**

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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;