3
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go
generated
vendored
3
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go
generated
vendored
@@ -1,4 +1,5 @@
|
||||
//+build !windows
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package wguser
|
||||
|
||||
|
||||
182
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go
generated
vendored
182
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go
generated
vendored
@@ -1,17 +1,15 @@
|
||||
//+build windows
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/ipc/winpipe"
|
||||
"golang.zx2c4.com/wireguard/ipc/namedpipe"
|
||||
)
|
||||
|
||||
// Expected prefixes when dealing with named pipes.
|
||||
@@ -22,182 +20,14 @@ const (
|
||||
|
||||
// dial is the default implementation of Client.dial.
|
||||
func dial(device string) (net.Conn, error) {
|
||||
// Thanks to @zx2c4 for the sample code that makes this possible:
|
||||
// https://github.com/WireGuard/wgctrl-go/issues/36#issuecomment-491912143.
|
||||
//
|
||||
// See also:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/secauthz/impersonation-tokens
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-reverttoself
|
||||
//
|
||||
// All of these operations require a locked OS thread for the duration of
|
||||
// this function. Once the pipe is opened successfully, RevertToSelf
|
||||
// terminates the impersonation of a client application.
|
||||
runtime.LockOSThread()
|
||||
defer func() {
|
||||
// Terminate the token impersonation operation. Per the Microsoft
|
||||
// documentation, the process should shut down if RevertToSelf fails.
|
||||
if err := windows.RevertToSelf(); err != nil {
|
||||
panicf("wguser: failed to terminate token impersonation, panicking per Microsoft recommendation: %v", err)
|
||||
}
|
||||
|
||||
runtime.UnlockOSThread()
|
||||
}()
|
||||
|
||||
privileges := windows.Tokenprivileges{
|
||||
PrivilegeCount: 1,
|
||||
Privileges: [1]windows.LUIDAndAttributes{
|
||||
{
|
||||
Attributes: windows.SE_PRIVILEGE_ENABLED,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := windows.LookupPrivilegeValue(
|
||||
nil,
|
||||
windows.StringToUTF16Ptr("SeDebugPrivilege"),
|
||||
&privileges.Privileges[0].Luid,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(processes)
|
||||
|
||||
e := windows.ProcessEntry32{
|
||||
Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{})),
|
||||
}
|
||||
|
||||
// Iterate the process list looking for any processes named winlogon.exe.
|
||||
//
|
||||
// It is possible for an attacker to attempt a denial of service of this
|
||||
// application by creating bogus processes with that name, so we must
|
||||
// attempt dialing a connection for each matching process until we either
|
||||
// succeed or run out of processes to try.
|
||||
//
|
||||
// It is unlikely that an attacker's process could appear before the true
|
||||
// winlogon.exe in this list, but better safe than sorry.
|
||||
for err := windows.Process32First(processes, &e); ; err = windows.Process32Next(processes, &e) {
|
||||
// Handle any errors from process list iteration.
|
||||
switch err {
|
||||
case nil:
|
||||
// Keep iterating processes.
|
||||
case windows.ERROR_NO_MORE_FILES:
|
||||
// No more files to check.
|
||||
return nil, errors.New("wguser: unable to find suitable winlogon.exe process to communicate with WireGuard")
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.ToLower(windows.UTF16ToString(e.ExeFile[:])) != "winlogon.exe" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Can we communicate with the device by impersonating this process?
|
||||
c, err := tryDial(device, e.ProcessID, privileges)
|
||||
switch {
|
||||
case err == nil:
|
||||
// Success, use this connection.
|
||||
return c, nil
|
||||
case os.IsPermission(err):
|
||||
// We found a process named winlogon.exe that doesn't have permission
|
||||
// to open a handle to the WireGuard device. Skip it and keep trying.
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tryDial attempts to impersonate the security token of pid to dial device.
|
||||
// tryDial _must_ only be invoked by dial.
|
||||
func tryDial(device string, pid uint32, privileges windows.Tokenprivileges) (net.Conn, error) {
|
||||
// Revert to normal thread state before attempting any further manipulation.
|
||||
// See comment in dial about the panic.
|
||||
if err := windows.RevertToSelf(); err != nil {
|
||||
panicf("wguser: failed to terminate token impersonation, panicking per Microsoft recommendation: %v", err)
|
||||
}
|
||||
|
||||
if err := windows.ImpersonateSelf(windows.SecurityImpersonation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
thread, err := windows.GetCurrentThread()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(thread)
|
||||
|
||||
var ttok windows.Token
|
||||
err = windows.OpenThreadToken(
|
||||
thread,
|
||||
windows.TOKEN_ADJUST_PRIVILEGES,
|
||||
false,
|
||||
&ttok,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ttok.Close()
|
||||
|
||||
err = windows.AdjustTokenPrivileges(
|
||||
ttok,
|
||||
false,
|
||||
&privileges,
|
||||
uint32(unsafe.Sizeof(privileges)),
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proc, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(proc)
|
||||
|
||||
var ptok windows.Token
|
||||
err = windows.OpenProcessToken(
|
||||
proc,
|
||||
windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE,
|
||||
&ptok,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ptok.Close()
|
||||
|
||||
var dup windows.Token
|
||||
err = windows.DuplicateTokenEx(
|
||||
ptok,
|
||||
0,
|
||||
nil,
|
||||
windows.SecurityImpersonation,
|
||||
windows.TokenImpersonation,
|
||||
&dup,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dup.Close()
|
||||
|
||||
if err := windows.SetThreadToken(nil, dup); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localSystem, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeCfg := &winpipe.DialConfig{
|
||||
return (&namedpipe.DialConfig{
|
||||
ExpectedOwner: localSystem,
|
||||
}
|
||||
return winpipe.Dial(device, nil, pipeCfg)
|
||||
}).DialTimeout(device, time.Duration(0))
|
||||
}
|
||||
|
||||
// find is the default implementation of Client.find.
|
||||
|
||||
Reference in New Issue
Block a user