aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-03 02:24:32 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-03 10:34:25 +0100
commit19d6227c1de4d19363a5f63d0e26c91a776defbd (patch)
tree422229c923ef0e430ba1af38d65780ddc1c233aa
parentapi: refactor .inf parsing and check SystemTimeToFileTime for errors (diff)
downloadwintun-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.c9
-rw-r--r--api/elevate.c56
-rw-r--r--api/elevate.h3
-rw-r--r--api/rundll32.h16
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)
{