api: rundll32: repair token spawning semantics
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
a73927ea6c
commit
19d6227c1d
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -9,3 +9,6 @@
|
||||
|
||||
BOOL
|
||||
ElevateToSystem(void);
|
||||
|
||||
HANDLE
|
||||
GetPrimarySystemTokenFromThread(void);
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user