aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/adapter.c51
-rw-r--r--api/api.vcxproj2
-rw-r--r--api/api.vcxproj.filters6
-rw-r--r--api/elevate.c101
-rw-r--r--api/elevate.h9
-rw-r--r--api/pch.h1
-rw-r--r--api/rundll32.c97
-rw-r--r--api/session.c27
8 files changed, 179 insertions, 115 deletions
diff --git a/api/adapter.c b/api/adapter.c
index 8ace66c..1006384 100644
--- a/api/adapter.c
+++ b/api/adapter.c
@@ -597,10 +597,16 @@ WintunGetAdapter(
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name,
_Out_ WINTUN_ADAPTER **Adapter)
{
+ if (!ElevateToSystem())
+ return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
+
DWORD Result;
HANDLE Mutex = NamespaceTakeMutex(Pool);
if (!Mutex)
- return ERROR_INVALID_HANDLE;
+ {
+ Result = ERROR_INVALID_HANDLE;
+ goto cleanupToken;
+ }
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
@@ -675,6 +681,8 @@ cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanupMutex:
NamespaceReleaseMutex(Mutex);
+cleanupToken:
+ RevertToSelf();
return Result;
}
@@ -1562,15 +1570,25 @@ WintunCreateAdapter(
_Out_ WINTUN_ADAPTER **Adapter,
_Inout_ BOOL *RebootRequired)
{
+ if (!ElevateToSystem())
+ return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
+
+ DWORD Result = ERROR_SUCCESS;
#ifdef MAYBE_WOW64
if (NativeMachine != IMAGE_FILE_PROCESS)
- return CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired);
+ {
+ Result = CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired);
+ RevertToSelf();
+ return Result;
+ }
#endif
- DWORD Result = ERROR_SUCCESS;
WCHAR RandomTempSubDirectory[MAX_PATH];
if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS)
- return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result;
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
+ goto cleanupToken;
+ }
WCHAR CatPath[MAX_PATH] = { 0 };
WCHAR SysPath[MAX_PATH] = { 0 };
@@ -1619,6 +1637,8 @@ cleanupDelete:
DeleteFileW(InfPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
+cleanupToken:
+ RevertToSelf();
return Result;
}
@@ -1663,20 +1683,31 @@ cleanupArgv:
WINTUN_STATUS WINAPI
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired)
{
+ if (!ElevateToSystem())
+ return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
+
+ DWORD Result;
#ifdef MAYBE_WOW64
if (NativeMachine != IMAGE_FILE_PROCESS)
- return DeleteAdapterNatively(Adapter, RebootRequired);
+ {
+ Result = DeleteAdapterNatively(Adapter, RebootRequired);
+ RevertToSelf();
+ return Result;
+ }
#endif
HDEVINFO DevInfo;
SP_DEVINFO_DATA DevInfoData;
- DWORD Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData);
+ Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData);
if (Result == ERROR_FILE_NOT_FOUND)
- return ERROR_SUCCESS;
- if (Result != ERROR_SUCCESS)
+ {
+ Result = ERROR_SUCCESS;
+ goto cleanupToken;
+ }
+ else if (Result != ERROR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get device info data");
- return Result;
+ goto cleanupToken;
}
SetQuietInstall(DevInfo, &DevInfoData);
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
@@ -1689,6 +1720,8 @@ WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequ
else
Result = LOG_LAST_ERROR(L"Unable to remove existing adapter");
SetupDiDestroyDeviceInfoList(DevInfo);
+cleanupToken:
+ RevertToSelf();
return Result;
}
diff --git a/api/api.vcxproj b/api/api.vcxproj
index 3c7dca7..12ae6ca 100644
--- a/api/api.vcxproj
+++ b/api/api.vcxproj
@@ -195,6 +195,7 @@
<ClInclude Include="api.h" />
<ClInclude Include="adapter.h" />
<ClInclude Include="atomic.h" />
+ <ClInclude Include="elevate.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="namespace.h" />
<ClInclude Include="nci.h" />
@@ -206,6 +207,7 @@
<ItemGroup>
<ClCompile Include="api.c" />
<ClCompile Include="adapter.c" />
+ <ClCompile Include="elevate.c" />
<ClCompile Include="logger.c" />
<ClCompile Include="namespace.c" />
<ClCompile Include="nci.c" />
diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters
index e59284e..090a1ef 100644
--- a/api/api.vcxproj.filters
+++ b/api/api.vcxproj.filters
@@ -55,6 +55,9 @@
<ClInclude Include="atomic.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="elevate.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="api.c">
@@ -87,5 +90,8 @@
<ClCompile Include="session.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="elevate.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/api/elevate.c b/api/elevate.c
new file mode 100644
index 0000000..9baaa97
--- /dev/null
+++ b/api/elevate.c
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "pch.h"
+
+BOOL
+ElevateToSystem(void)
+{
+ HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
+ PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) };
+ BOOL Ret;
+ DWORD LastError = ERROR_SUCCESS;
+ 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);
+ LastError = GetLastError();
+ if (!Ret)
+ goto cleanup;
+ Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
+ LastError = GetLastError();
+ if (!Ret)
+ goto cleanup;
+ Ret =
+ GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
+ LastError = GetLastError();
+ CloseHandle(CurrentProcessToken);
+ if (!Ret)
+ goto cleanup;
+ if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
+ return TRUE;
+ Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
+ LastError = GetLastError();
+ if (!Ret)
+ goto cleanup;
+ ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ LastError = GetLastError();
+ if (ProcessSnapshot == INVALID_HANDLE_VALUE)
+ goto cleanup;
+ for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret;
+ Ret = Process32NextW(ProcessSnapshot, &ProcessEntry))
+ {
+ if (_wcsicmp(ProcessEntry.szExeFile, L"winlogon.exe"))
+ continue;
+ RevertToSelf();
+ Ret = ImpersonateSelf(SecurityImpersonation);
+ LastError = GetLastError();
+ if (!Ret)
+ continue;
+ Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
+ LastError = GetLastError();
+ if (!Ret)
+ continue;
+ Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
+ LastError = GetLastError();
+ CloseHandle(ThreadToken);
+ if (!Ret)
+ continue;
+
+ WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
+ LastError = GetLastError();
+ if (!WinlogonProcess)
+ continue;
+ Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
+ LastError = GetLastError();
+ CloseHandle(WinlogonProcess);
+ if (!Ret)
+ continue;
+ Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken);
+ LastError = GetLastError();
+ CloseHandle(WinlogonToken);
+ if (!Ret)
+ continue;
+ if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
+ goto next;
+ if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
+ goto next;
+ if (!SetThreadToken(NULL, DuplicatedToken))
+ goto next;
+ CloseHandle(DuplicatedToken);
+ CloseHandle(ProcessSnapshot);
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+ next:
+ LastError = GetLastError();
+ CloseHandle(DuplicatedToken);
+ }
+ RevertToSelf();
+ CloseHandle(ProcessSnapshot);
+cleanup:
+ SetLastError(LastError);
+ return FALSE;
+}
diff --git a/api/elevate.h b/api/elevate.h
new file mode 100644
index 0000000..5a3b70c
--- /dev/null
+++ b/api/elevate.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+BOOL
+ElevateToSystem(void);
diff --git a/api/pch.h b/api/pch.h
index 3898a76..bb5b3a1 100644
--- a/api/pch.h
+++ b/api/pch.h
@@ -8,6 +8,7 @@
#include "adapter.h"
#include "atomic.h"
#include "api.h"
+#include "elevate.h"
#include "logger.h"
#include "namespace.h"
#include "nci.h"
diff --git a/api/rundll32.c b/api/rundll32.c
index ae722b5..ac678a5 100644
--- a/api/rundll32.c
+++ b/api/rundll32.c
@@ -56,101 +56,6 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ const WCHAR *LogLine)
return TRUE;
}
-static BOOL
-ElevateToSystem(void)
-{
- HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
- PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) };
- BOOL Ret;
- DWORD LastError = ERROR_SUCCESS;
- 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);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- Ret =
- GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
- LastError = GetLastError();
- CloseHandle(CurrentProcessToken);
- if (!Ret)
- goto cleanup;
- if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
- return TRUE;
- Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- LastError = GetLastError();
- if (ProcessSnapshot == INVALID_HANDLE_VALUE)
- goto cleanup;
- for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret;
- Ret = Process32NextW(ProcessSnapshot, &ProcessEntry))
- {
- if (_wcsicmp(ProcessEntry.szExeFile, L"winlogon.exe"))
- continue;
- RevertToSelf();
- Ret = ImpersonateSelf(SecurityImpersonation);
- LastError = GetLastError();
- if (!Ret)
- continue;
- Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
- LastError = GetLastError();
- if (!Ret)
- continue;
- Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
- LastError = GetLastError();
- CloseHandle(ThreadToken);
- if (!Ret)
- continue;
-
- WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
- LastError = GetLastError();
- if (!WinlogonProcess)
- continue;
- Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
- LastError = GetLastError();
- CloseHandle(WinlogonProcess);
- if (!Ret)
- continue;
- Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken);
- LastError = GetLastError();
- CloseHandle(WinlogonToken);
- if (!Ret)
- continue;
- if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
- goto next;
- if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
- goto next;
- if (!SetThreadToken(NULL, DuplicatedToken))
- goto next;
- CloseHandle(DuplicatedToken);
- CloseHandle(ProcessSnapshot);
- SetLastError(ERROR_SUCCESS);
- return TRUE;
- next:
- LastError = GetLastError();
- CloseHandle(DuplicatedToken);
- }
- RevertToSelf();
- CloseHandle(ProcessSnapshot);
-cleanup:
- SetLastError(LastError);
- return FALSE;
-}
-
static int Argc;
static WCHAR **Argv;
@@ -159,13 +64,11 @@ Init(void)
{
WintunSetLogger(ConsoleLogger);
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
- ElevateToSystem();
}
static void
Done(void)
{
- RevertToSelf();
LocalFree(Argv);
}
diff --git a/api/session.c b/api/session.c
index 259b1f5..f850c44 100644
--- a/api/session.c
+++ b/api/session.c
@@ -78,13 +78,19 @@ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out
Result = LOG_LAST_ERROR(L"Failed to allocate ring memory");
goto cleanupRings;
}
+ if (!ElevateToSystem())
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user");
+ Result = ERROR_ACCESS_DENIED;
+ goto cleanupAllocatedRegion;
+ }
(*Session)->Descriptor.Send.RingSize = RingSize;
(*Session)->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
(*Session)->Descriptor.Send.TailMoved = CreateEventW(SecurityAttributes, FALSE, FALSE, NULL);
if (!(*Session)->Descriptor.Send.TailMoved)
{
Result = LOG_LAST_ERROR(L"Failed to create send event");
- goto cleanupAllocatedRegion;
+ goto cleanupToken;
}
(*Session)->Descriptor.Receive.RingSize = RingSize;
@@ -104,18 +110,19 @@ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out
}
DWORD BytesReturned;
if (!DeviceIoControl(
- (*Session)->Handle,
- TUN_IOCTL_REGISTER_RINGS,
- &(*Session)->Descriptor,
- sizeof(TUN_REGISTER_RINGS),
- NULL,
- 0,
- &BytesReturned,
+ (*Session)->Handle,
+ TUN_IOCTL_REGISTER_RINGS,
+ &(*Session)->Descriptor,
+ sizeof(TUN_REGISTER_RINGS),
+ NULL,
+ 0,
+ &BytesReturned,
NULL))
{
Result = LOG_LAST_ERROR(L"Failed to perform ioctl");
goto cleanupHandle;
}
+ RevertToSelf();
(*Session)->Capacity = Capacity;
(void)InitializeCriticalSectionAndSpinCount(&(*Session)->Receive.Lock, LOCK_SPIN_COUNT);
(void)InitializeCriticalSectionAndSpinCount(&(*Session)->Send.Lock, LOCK_SPIN_COUNT);
@@ -126,6 +133,8 @@ cleanupReceiveTailMoved:
CloseHandle((*Session)->Descriptor.Receive.TailMoved);
cleanupSendTailMoved:
CloseHandle((*Session)->Descriptor.Send.TailMoved);
+cleanupToken:
+ RevertToSelf();
cleanupAllocatedRegion:
VirtualFree(AllocatedRegion, 0, MEM_RELEASE);
cleanupRings:
@@ -137,7 +146,7 @@ cleanupRings:
void WINAPI
WintunEndSession(_In_ TUN_SESSION *Session)
{
- SetEvent(Session->Descriptor.Send.TailMoved); // wake the reader if it's sleeping
+ SetEvent(Session->Descriptor.Send.TailMoved); // Wake the reader if it's sleeping.
DeleteCriticalSection(&Session->Send.Lock);
DeleteCriticalSection(&Session->Receive.Lock);
CloseHandle(Session->Handle);