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)
|
WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTUN_ADAPTER **Adapter)
|
||||||
{
|
{
|
||||||
if (!ElevateToSystem())
|
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;
|
DWORD Result;
|
||||||
HANDLE Mutex = NamespaceTakePoolMutex(Pool);
|
HANDLE Mutex = NamespaceTakePoolMutex(Pool);
|
||||||
if (!Mutex)
|
if (!Mutex)
|
||||||
@ -1681,7 +1680,7 @@ WintunCreateAdapter(
|
|||||||
_Out_opt_ BOOL *RebootRequired)
|
_Out_opt_ BOOL *RebootRequired)
|
||||||
{
|
{
|
||||||
if (!ElevateToSystem())
|
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;
|
BOOL DummyRebootRequired;
|
||||||
if (!RebootRequired)
|
if (!RebootRequired)
|
||||||
RebootRequired = &DummyRebootRequired;
|
RebootRequired = &DummyRebootRequired;
|
||||||
@ -1699,7 +1698,7 @@ WINTUN_STATUS WINAPI
|
|||||||
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired)
|
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired)
|
||||||
{
|
{
|
||||||
if (!ElevateToSystem())
|
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;
|
BOOL DummyRebootRequired;
|
||||||
if (!RebootRequired)
|
if (!RebootRequired)
|
||||||
@ -1790,7 +1789,7 @@ WINTUN_STATUS WINAPI
|
|||||||
WintunDeleteDriver(void)
|
WintunDeleteDriver(void)
|
||||||
{
|
{
|
||||||
if (!ElevateToSystem())
|
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;
|
DWORD Result = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -102,3 +102,59 @@ cleanup:
|
|||||||
SetLastError(LastError);
|
SetLastError(LastError);
|
||||||
return FALSE;
|
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
|
BOOL
|
||||||
ElevateToSystem(void);
|
ElevateToSystem(void);
|
||||||
|
|
||||||
|
HANDLE
|
||||||
|
GetPrimarySystemTokenFromThread(void);
|
@ -157,8 +157,8 @@ ExecuteRunDll32(
|
|||||||
.Response = Response,
|
.Response = Response,
|
||||||
.ResponseCapacity = ResponseCapacity };
|
.ResponseCapacity = ResponseCapacity };
|
||||||
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
|
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
|
||||||
if ((ThreadStdout = CreateThread(&SecurityAttributes, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
||||||
(ThreadStderr = CreateThread(&SecurityAttributes, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to spawn readers");
|
Result = LOG_LAST_ERROR(L"Failed to spawn readers");
|
||||||
goto cleanupThreads;
|
goto cleanupThreads;
|
||||||
@ -169,14 +169,22 @@ ExecuteRunDll32(
|
|||||||
.hStdOutput = StreamWStdout,
|
.hStdOutput = StreamWStdout,
|
||||||
.hStdError = StreamWStderr };
|
.hStdError = StreamWStderr };
|
||||||
PROCESS_INFORMATION pi;
|
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;
|
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);
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
|
cleanupToken:
|
||||||
|
CloseHandle(ProcessToken);
|
||||||
cleanupThreads:
|
cleanupThreads:
|
||||||
if (ThreadStderr)
|
if (ThreadStderr)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user