api: manipulate process token if thread token didn't require impersonation

Otherwise rundll32.exe fails if we're already SYSTEM.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2020-11-06 17:05:56 +01:00
parent c581a9f6cd
commit 3dbaafd4ae

View File

@ -124,7 +124,7 @@ cleanup:
_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void) _Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void)
{ {
HANDLE CurrentThreadToken, DuplicatedToken; HANDLE CurrentToken, DuplicatedToken;
BOOL Ret; BOOL Ret;
DWORD LastError; DWORD LastError;
TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } }; TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } };
@ -143,13 +143,16 @@ _Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(voi
return NULL; return NULL;
} }
Ret = OpenThreadToken( Ret = OpenThreadToken(
GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken); GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentToken);
if (!Ret && GetLastError() == ERROR_NO_TOKEN)
Ret = OpenProcessToken(
GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, &CurrentToken);
if (!Ret) if (!Ret)
{ {
LastError = LOG_LAST_ERROR(L"Failed to open thread token"); LastError = LOG_LAST_ERROR(L"Failed to open token");
return NULL; return NULL;
} }
Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); Ret = GetTokenInformation(CurrentToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
if (!Ret) if (!Ret)
{ {
LastError = LOG_LAST_ERROR(L"Failed to get token information"); LastError = LOG_LAST_ERROR(L"Failed to get token information");
@ -167,14 +170,14 @@ _Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(voi
LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value"); LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value");
goto cleanup; goto cleanup;
} }
Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); Ret = AdjustTokenPrivileges(CurrentToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
if (!Ret) if (!Ret)
{ {
LastError = LOG_LAST_ERROR(L"Failed to adjust token privileges"); LastError = LOG_LAST_ERROR(L"Failed to adjust token privileges");
goto cleanup; goto cleanup;
} }
Ret = DuplicateTokenEx( Ret = DuplicateTokenEx(
CurrentThreadToken, CurrentToken,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
NULL, NULL,
SecurityImpersonation, SecurityImpersonation,
@ -185,11 +188,11 @@ _Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(voi
LastError = LOG_LAST_ERROR(L"Failed to duplicate token"); LastError = LOG_LAST_ERROR(L"Failed to duplicate token");
goto cleanup; goto cleanup;
} }
CloseHandle(CurrentThreadToken); CloseHandle(CurrentToken);
return DuplicatedToken; return DuplicatedToken;
cleanup: cleanup:
CloseHandle(CurrentThreadToken); CloseHandle(CurrentToken);
SetLastError(LastError); SetLastError(LastError);
return NULL; return NULL;
} }