diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-03 02:24:32 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-03 10:34:25 +0100 |
commit | 19d6227c1de4d19363a5f63d0e26c91a776defbd (patch) | |
tree | 422229c923ef0e430ba1af38d65780ddc1c233aa | |
parent | api: refactor .inf parsing and check SystemTimeToFileTime for errors (diff) | |
download | wintun-19d6227c1de4d19363a5f63d0e26c91a776defbd.tar.xz wintun-19d6227c1de4d19363a5f63d0e26c91a776defbd.zip |
api: rundll32: repair token spawning semantics
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | api/adapter.c | 9 | ||||
-rw-r--r-- | api/elevate.c | 56 | ||||
-rw-r--r-- | api/elevate.h | 3 | ||||
-rw-r--r-- | api/rundll32.h | 16 |
4 files changed, 75 insertions, 9 deletions
diff --git a/api/adapter.c b/api/adapter.c index 45ff38f..86eef0f 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -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; diff --git a/api/elevate.c b/api/elevate.c index e9bab7f..e89a54c 100644 --- a/api/elevate.c +++ b/api/elevate.c @@ -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; +} diff --git a/api/elevate.h b/api/elevate.h index ec054ba..5f2cbbd 100644 --- a/api/elevate.h +++ b/api/elevate.h @@ -9,3 +9,6 @@ BOOL ElevateToSystem(void); + +HANDLE +GetPrimarySystemTokenFromThread(void);
\ No newline at end of file diff --git a/api/rundll32.h b/api/rundll32.h index 61df869..51ea321 100644 --- a/api/rundll32.h +++ b/api/rundll32.h @@ -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) { |