ipc: remove windows elevation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
d58df7ed10
commit
c70bea7a31
|
@ -14,102 +14,37 @@
|
||||||
|
|
||||||
static FILE *userspace_interface_file(const char *iface)
|
static FILE *userspace_interface_file(const char *iface)
|
||||||
{
|
{
|
||||||
char fname[MAX_PATH], error_message[1024 * 128] = { 0 };
|
char fname[MAX_PATH];
|
||||||
HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token, pipe_handle = INVALID_HANDLE_VALUE;
|
HANDLE pipe_handle;
|
||||||
PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) };
|
|
||||||
PSECURITY_DESCRIPTOR pipe_sd;
|
|
||||||
PSID pipe_sid;
|
|
||||||
SID expected_sid;
|
SID expected_sid;
|
||||||
BOOL ret;
|
DWORD bytes = sizeof(expected_sid);
|
||||||
|
PSID pipe_sid;
|
||||||
|
PSECURITY_DESCRIPTOR pipe_sd;
|
||||||
|
bool equal;
|
||||||
int fd;
|
int fd;
|
||||||
DWORD last_error = ERROR_SUCCESS, bytes = sizeof(expected_sid);
|
|
||||||
TOKEN_PRIVILEGES privileges = {
|
|
||||||
.PrivilegeCount = 1,
|
|
||||||
.Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
|
|
||||||
goto err;
|
|
||||||
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes))
|
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface);
|
||||||
if (process_snapshot == INVALID_HANDLE_VALUE)
|
pipe_handle = CreateFileA(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
goto err;
|
if (pipe_handle == INVALID_HANDLE_VALUE)
|
||||||
for (ret = Process32First(process_snapshot, &entry); ret; last_error = GetLastError(), ret = Process32Next(process_snapshot, &entry)) {
|
|
||||||
if (strcasecmp(entry.szExeFile, "winlogon.exe"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
RevertToSelf();
|
|
||||||
if (!ImpersonateSelf(SecurityImpersonation))
|
|
||||||
continue;
|
|
||||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
|
|
||||||
continue;
|
|
||||||
if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) {
|
|
||||||
last_error = GetLastError();
|
|
||||||
CloseHandle(thread_token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(thread_token);
|
|
||||||
|
|
||||||
winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID);
|
|
||||||
if (!winlogon_process)
|
|
||||||
continue;
|
|
||||||
if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
|
|
||||||
continue;
|
|
||||||
CloseHandle(winlogon_process);
|
|
||||||
if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) {
|
|
||||||
last_error = GetLastError();
|
|
||||||
RevertToSelf();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(winlogon_token);
|
|
||||||
if (!SetThreadToken(NULL, duplicated_token)) {
|
|
||||||
last_error = GetLastError();
|
|
||||||
CloseHandle(duplicated_token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(duplicated_token);
|
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface);
|
|
||||||
pipe_handle = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
||||||
last_error = GetLastError();
|
|
||||||
if (pipe_handle == INVALID_HANDLE_VALUE)
|
|
||||||
continue;
|
|
||||||
last_error = GetSecurityInfo(pipe_handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pipe_sid, NULL, NULL, NULL, &pipe_sd);
|
|
||||||
if (last_error != ERROR_SUCCESS) {
|
|
||||||
CloseHandle(pipe_handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
last_error = EqualSid(&expected_sid, pipe_sid) ? ERROR_SUCCESS : ERROR_ACCESS_DENIED;
|
|
||||||
LocalFree(pipe_sd);
|
|
||||||
if (last_error != ERROR_SUCCESS) {
|
|
||||||
CloseHandle(pipe_handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
last_error = ERROR_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
RevertToSelf();
|
|
||||||
CloseHandle(process_snapshot);
|
|
||||||
|
|
||||||
if (last_error != ERROR_SUCCESS || pipe_handle == INVALID_HANDLE_VALUE)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
if (GetSecurityInfo(pipe_handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pipe_sid, NULL, NULL, NULL, &pipe_sd) != ERROR_SUCCESS)
|
||||||
|
goto err_close;
|
||||||
|
equal = EqualSid(&expected_sid, pipe_sid);
|
||||||
|
LocalFree(pipe_sd);
|
||||||
|
if (!equal)
|
||||||
|
goto err_close;
|
||||||
fd = _open_osfhandle((intptr_t)pipe_handle, _O_RDWR);
|
fd = _open_osfhandle((intptr_t)pipe_handle, _O_RDWR);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
last_error = GetLastError();
|
|
||||||
CloseHandle(pipe_handle);
|
CloseHandle(pipe_handle);
|
||||||
goto err;
|
return NULL;
|
||||||
}
|
}
|
||||||
return _fdopen(fd, "r+");
|
return _fdopen(fd, "r+");
|
||||||
|
err_close:
|
||||||
|
CloseHandle(pipe_handle);
|
||||||
err:
|
err:
|
||||||
if (last_error == ERROR_SUCCESS)
|
|
||||||
last_error = GetLastError();
|
|
||||||
if (last_error == ERROR_SUCCESS)
|
|
||||||
last_error = ERROR_ACCESS_DENIED;
|
|
||||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, sizeof(error_message) - 1, NULL);
|
|
||||||
fprintf(stderr, "Error: Unable to open IPC handle via SYSTEM impersonation: %ld: %s\n", last_error, error_message);
|
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,66 +311,6 @@ skip:;
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL elevated_ioctl(HANDLE handle, DWORD code, void *in_buf, DWORD in_buf_len, void *out_buf, DWORD out_buf_len, DWORD *bytes_returned)
|
|
||||||
{
|
|
||||||
HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
|
|
||||||
PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) };
|
|
||||||
TOKEN_PRIVILEGES privileges = {
|
|
||||||
.PrivilegeCount = 1,
|
|
||||||
.Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }}
|
|
||||||
};
|
|
||||||
SID expected_sid;
|
|
||||||
DWORD bytes = sizeof(expected_sid);
|
|
||||||
BOOL ret;
|
|
||||||
|
|
||||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
|
|
||||||
return FALSE;
|
|
||||||
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
||||||
if (process_snapshot == INVALID_HANDLE_VALUE)
|
|
||||||
return FALSE;
|
|
||||||
for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry)) {
|
|
||||||
if (strcasecmp(entry.szExeFile, "winlogon.exe"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
RevertToSelf();
|
|
||||||
if (!ImpersonateSelf(SecurityImpersonation))
|
|
||||||
continue;
|
|
||||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
|
|
||||||
continue;
|
|
||||||
if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) {
|
|
||||||
CloseHandle(thread_token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(thread_token);
|
|
||||||
|
|
||||||
winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID);
|
|
||||||
if (!winlogon_process)
|
|
||||||
continue;
|
|
||||||
if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
|
|
||||||
continue;
|
|
||||||
CloseHandle(winlogon_process);
|
|
||||||
if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) {
|
|
||||||
RevertToSelf();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(winlogon_token);
|
|
||||||
if (!SetThreadToken(NULL, duplicated_token)) {
|
|
||||||
CloseHandle(duplicated_token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CloseHandle(duplicated_token);
|
|
||||||
ret = DeviceIoControl(handle, code, in_buf, in_buf_len, out_buf, out_buf_len, bytes_returned, NULL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RevertToSelf();
|
|
||||||
CloseHandle(process_snapshot);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kernel_get_device(struct wgdevice **device, const char *iface)
|
static int kernel_get_device(struct wgdevice **device, const char *iface)
|
||||||
{
|
{
|
||||||
WG_IOCTL_INTERFACE *wg_iface;
|
WG_IOCTL_INTERFACE *wg_iface;
|
||||||
|
@ -389,10 +329,10 @@ static int kernel_get_device(struct wgdevice **device, const char *iface)
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
while (!elevated_ioctl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len)) {
|
while (!DeviceIoControl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len, NULL)) {
|
||||||
free(buf);
|
free(buf);
|
||||||
if (GetLastError() != ERROR_MORE_DATA) {
|
if (GetLastError() != ERROR_MORE_DATA) {
|
||||||
errno = EIO;
|
errno = EACCES;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
buf = malloc(buf_len);
|
buf = malloc(buf_len);
|
||||||
|
@ -500,10 +440,10 @@ out:
|
||||||
|
|
||||||
static int kernel_set_device(struct wgdevice *dev)
|
static int kernel_set_device(struct wgdevice *dev)
|
||||||
{
|
{
|
||||||
WG_IOCTL_INTERFACE *wg_iface;
|
WG_IOCTL_INTERFACE *wg_iface = NULL;
|
||||||
WG_IOCTL_PEER *wg_peer;
|
WG_IOCTL_PEER *wg_peer;
|
||||||
WG_IOCTL_ALLOWED_IP *wg_aip;
|
WG_IOCTL_ALLOWED_IP *wg_aip;
|
||||||
size_t buf_len = sizeof(WG_IOCTL_INTERFACE);
|
DWORD buf_len = sizeof(WG_IOCTL_INTERFACE);
|
||||||
HANDLE handle = kernel_interface_handle(dev->name);
|
HANDLE handle = kernel_interface_handle(dev->name);
|
||||||
struct wgpeer *peer;
|
struct wgpeer *peer;
|
||||||
struct wgallowedip *aip;
|
struct wgallowedip *aip;
|
||||||
|
@ -514,13 +454,22 @@ static int kernel_set_device(struct wgdevice *dev)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
for_each_wgpeer(dev, peer) {
|
for_each_wgpeer(dev, peer) {
|
||||||
|
if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_PEER)) {
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
buf_len += sizeof(WG_IOCTL_PEER);
|
buf_len += sizeof(WG_IOCTL_PEER);
|
||||||
for_each_wgallowedip(peer, aip)
|
for_each_wgallowedip(peer, aip) {
|
||||||
|
if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_ALLOWED_IP)) {
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
buf_len += sizeof(WG_IOCTL_ALLOWED_IP);
|
buf_len += sizeof(WG_IOCTL_ALLOWED_IP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wg_iface = calloc(1, buf_len);
|
wg_iface = calloc(1, buf_len);
|
||||||
if (!wg_iface)
|
if (!wg_iface)
|
||||||
return -errno;
|
goto out;
|
||||||
|
|
||||||
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
|
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
|
||||||
memcpy(wg_iface->PrivateKey, dev->private_key, sizeof(wg_iface->PrivateKey));
|
memcpy(wg_iface->PrivateKey, dev->private_key, sizeof(wg_iface->PrivateKey));
|
||||||
|
@ -586,8 +535,10 @@ static int kernel_set_device(struct wgdevice *dev)
|
||||||
}
|
}
|
||||||
wg_iface->PeersCount = peer_count;
|
wg_iface->PeersCount = peer_count;
|
||||||
|
|
||||||
if (!elevated_ioctl(handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len))
|
if (!DeviceIoControl(handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len, NULL)) {
|
||||||
|
errno = EACCES;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
Loading…
Reference in New Issue