aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--attacksurface.md2
-rw-r--r--main.go2
-rw-r--r--services/tokens.go15
-rw-r--r--tunnel/service.go4
4 files changed, 17 insertions, 6 deletions
diff --git a/attacksurface.md b/attacksurface.md
index 7e1906b0..7b1f16ae 100644
--- a/attacksurface.md
+++ b/attacksurface.md
@@ -19,7 +19,7 @@ The tunnel service is a userspace service running as Local System, responsible f
- A listening pipe in `\\.\pipe\WireGuard\%s`, where `%s` is some basename of an already valid filename. Its permissions are set to `O:SYD:(A;;GA;;;SY)`, which presumably means only the "Local System" user can access it and do things, but it might be worth double checking that. This pipe gives access to private keys and allows for reconfiguration of the interface, as well as rebinding to different ports (below 1024, even).
- It handles data from its two UDP sockets, accessible to the public Internet.
- It handles data from Wintun, accessible to all users who can do anything with the network stack.
- - After some initial setup, it uses `AdjustTokenPrivileges` to remove all privileges.
+ - After some initial setup, it uses `AdjustTokenPrivileges` to remove all privileges, except for `SeLoadDriverPrivilege`, so that it can remove the interface when shutting down. This latter point is rather unfortunate, as `SeLoadDriverPrivilege` can be used for all sorts of interesting escalation. Future work includes forking an additional process or the like so that we can drop this from the main tunnel process.
### Manager Service
diff --git a/main.go b/main.go
index f642906e..5f2e08f3 100644
--- a/main.go
+++ b/main.go
@@ -171,7 +171,7 @@ func main() {
if len(os.Args) != 6 {
usage()
}
- err := services.DropAllPrivileges()
+ err := services.DropAllPrivileges(false)
if err != nil {
fatal(err)
}
diff --git a/services/tokens.go b/services/tokens.go
index ae89a185..bca75475 100644
--- a/services/tokens.go
+++ b/services/tokens.go
@@ -29,11 +29,18 @@ func TokenIsMemberOfBuiltInAdministrator(token windows.Token) bool {
return isAdmin
}
-func DropAllPrivileges() error {
+func DropAllPrivileges(retainDriverLoading bool) error {
processHandle, err := windows.GetCurrentProcess()
if err != nil {
return err
}
+ var luid windows.LUID
+ if retainDriverLoading {
+ err = windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr("SeLoadDriverPrivilege"), &luid)
+ if err != nil {
+ return err
+ }
+ }
var processToken windows.Token
err = windows.OpenProcessToken(processHandle, windows.TOKEN_READ|windows.TOKEN_WRITE, &processToken)
if err != nil {
@@ -57,7 +64,11 @@ func DropAllPrivileges() error {
}
tokenPrivileges := (*windows.Tokenprivileges)(unsafe.Pointer(&buffer[0]))
for i := uint32(0); i < tokenPrivileges.PrivilegeCount; i++ {
- (*windows.LUIDAndAttributes)(unsafe.Pointer(uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0])) + unsafe.Sizeof(tokenPrivileges.Privileges[0])*uintptr(i))).Attributes = windows.SE_PRIVILEGE_REMOVED
+ item := (*windows.LUIDAndAttributes)(unsafe.Pointer(uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0])) + unsafe.Sizeof(tokenPrivileges.Privileges[0])*uintptr(i)))
+ if retainDriverLoading && item.Luid == luid {
+ continue
+ }
+ item.Attributes = windows.SE_PRIVILEGE_REMOVED
}
err = windows.AdjustTokenPrivileges(processToken, false, tokenPrivileges, 0, nil, nil)
runtime.KeepAlive(buffer)
diff --git a/tunnel/service.go b/tunnel/service.go
index 70e2c8a1..dbf0dd6e 100644
--- a/tunnel/service.go
+++ b/tunnel/service.go
@@ -155,8 +155,8 @@ func (service *Service) Execute(args []string, r <-chan svc.ChangeRequest, chang
return
}
- log.Println("Dropping all privileges")
- err = services.DropAllPrivileges()
+ log.Println("Dropping privileges")
+ err = services.DropAllPrivileges(true)
if err != nil {
serviceError = services.ErrorDropPrivileges
return