api: rundll32: repair token spawning semantics

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2020-11-03 02:24:32 +01:00
parent a73927ea6c
commit 19d6227c1d
4 changed files with 75 additions and 9 deletions

View File

@ -593,8 +593,7 @@ WINTUN_STATUS WINAPI
WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTUN_ADAPTER **Adapter)
{
if (!ElevateToSystem())
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user");
DWORD Result;
HANDLE Mutex = NamespaceTakePoolMutex(Pool);
if (!Mutex)
@ -1681,7 +1680,7 @@ WintunCreateAdapter(
_Out_opt_ BOOL *RebootRequired)
{
if (!ElevateToSystem())
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user");
BOOL DummyRebootRequired;
if (!RebootRequired)
RebootRequired = &DummyRebootRequired;
@ -1699,7 +1698,7 @@ WINTUN_STATUS WINAPI
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired)
{
if (!ElevateToSystem())
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user");
BOOL DummyRebootRequired;
if (!RebootRequired)
@ -1790,7 +1789,7 @@ WINTUN_STATUS WINAPI
WintunDeleteDriver(void)
{
if (!ElevateToSystem())
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user");
DWORD Result = ERROR_SUCCESS;

View File

@ -102,3 +102,59 @@ cleanup:
SetLastError(LastError);
return FALSE;
}
HANDLE
GetPrimarySystemTokenFromThread(void)
{
HANDLE CurrentThreadToken, DuplicatedToken;
BOOL Ret;
DWORD LastError;
TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } };
CHAR LocalSystemSid[0x400];
DWORD RequiredBytes = sizeof(LocalSystemSid);
struct
{
TOKEN_USER MaybeLocalSystem;
CHAR LargeEnoughForLocalSystem[0x400];
} TokenUserBuffer;
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
if (!Ret)
return NULL;
Ret = OpenThreadToken(
GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken);
if (!Ret)
return NULL;
Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
LastError = GetLastError();
if (!Ret)
goto cleanup;
LastError = ERROR_ACCESS_DENIED;
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
goto cleanup;
Ret = LookupPrivilegeValueW(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &Privileges.Privileges[0].Luid);
LastError = GetLastError();
if (!Ret)
goto cleanup;
Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
LastError = GetLastError();
if (!Ret)
goto cleanup;
Ret = DuplicateTokenEx(
CurrentThreadToken,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
NULL,
SecurityImpersonation,
TokenPrimary,
&DuplicatedToken);
LastError = GetLastError();
if (!Ret)
goto cleanup;
CloseHandle(CurrentThreadToken);
return DuplicatedToken;
cleanup:
CloseHandle(CurrentThreadToken);
SetLastError(LastError);
return FALSE;
}

View File

@ -9,3 +9,6 @@
BOOL
ElevateToSystem(void);
HANDLE
GetPrimarySystemTokenFromThread(void);

View File

@ -157,8 +157,8 @@ ExecuteRunDll32(
.Response = Response,
.ResponseCapacity = ResponseCapacity };
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
if ((ThreadStdout = CreateThread(&SecurityAttributes, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(&SecurityAttributes, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
Result = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
@ -169,14 +169,22 @@ ExecuteRunDll32(
.hStdOutput = StreamWStdout,
.hStdError = StreamWStderr };
PROCESS_INFORMATION pi;
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
HANDLE ProcessToken = GetPrimarySystemTokenFromThread();
if (!ProcessToken)
{
Result = LOG_LAST_ERROR(L"Creating process failed");
Result = LOG_LAST_ERROR(L"Failed to get primary system token from thread");
goto cleanupThreads;
}
if (!CreateProcessAsUserW(ProcessToken, RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
Result = LOG_LAST_ERROR(L"Failed to create process");
goto cleanupToken;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cleanupToken:
CloseHandle(ProcessToken);
cleanupThreads:
if (ThreadStderr)
{