diff options
author | 2020-11-13 03:10:00 +0100 | |
---|---|---|
committer | 2020-11-22 22:00:32 +0100 | |
commit | 1c7606cea18e908cf76201ce1534b0afdc04cc89 (patch) | |
tree | 56c591b462989278a9bc89fafe927d7347122db5 /manager/service.go | |
parent | tunnel: only enable DNS blocking for 0/0 configs (diff) | |
download | wireguard-windows-1c7606cea18e908cf76201ce1534b0afdc04cc89.tar.xz wireguard-windows-1c7606cea18e908cf76201ce1534b0afdc04cc89.zip |
manager: allow S-1-5-32-556 users to launch a limited UI
I still have serious security reservations about this, both conceptually
-- should users be allowed to do this stuff? -- and pratically -- there
are issues with this implementation that need some examination.
TODO:
- Is that registry key a secure path? Should we double check it?
- Are we leaking handles to the unpriv'd process from the manager? Audit
this too.
- IPC notifications are blocking. Should we move this to a go routine to
mitigate DoS potential?
- Is GOB deserialization secure? Can an NCO user crash or RCE the
manager?
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'manager/service.go')
-rw-r--r-- | manager/service.go | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/manager/service.go b/manager/service.go index 6c3b039b..48ecd129 100644 --- a/manager/service.go +++ b/manager/service.go @@ -90,6 +90,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest aliveSessions := make(map[uint32]bool) procsLock := sync.Mutex{} stoppingManager := false + operatorGroupSid, _ := windows.CreateWellKnownSid(windows.WinBuiltinNetworkConfigurationOperatorsSid) startProcess := func(session uint32) { defer func() { @@ -104,7 +105,24 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest if err != nil { return } - if !elevate.TokenIsElevatedOrElevatable(userToken) { + isAdmin := elevate.TokenIsElevatedOrElevatable(userToken) + isOperator := false + if !isAdmin && conf.AdminBool("LimitedOperatorUI") && operatorGroupSid != nil { + linkedToken, err := userToken.GetLinkedToken() + var impersonationToken windows.Token + if err == nil { + err = windows.DuplicateTokenEx(linkedToken, windows.TOKEN_QUERY, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &impersonationToken) + linkedToken.Close() + } else { + err = windows.DuplicateTokenEx(userToken, windows.TOKEN_QUERY, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &impersonationToken) + } + if err == nil { + isOperator, err = impersonationToken.IsMember(operatorGroupSid) + isOperator = isOperator && err == nil + impersonationToken.Close() + } + } + if !isAdmin && !isOperator { userToken.Close() return } @@ -125,23 +143,28 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest return } userProfileDirectory, _ := userToken.GetUserProfileDirectory() - var elevatedToken windows.Token - if userToken.IsElevated() { - elevatedToken = userToken - } else { - elevatedToken, err = userToken.GetLinkedToken() - userToken.Close() - if err != nil { - log.Printf("Unable to elevate token: %v", err) - return - } - if !elevatedToken.IsElevated() { - elevatedToken.Close() - log.Println("Linked token is not elevated") - return + var elevatedToken, runToken windows.Token + if isAdmin { + if userToken.IsElevated() { + elevatedToken = userToken + } else { + elevatedToken, err = userToken.GetLinkedToken() + userToken.Close() + if err != nil { + log.Printf("Unable to elevate token: %v", err) + return + } + if !elevatedToken.IsElevated() { + elevatedToken.Close() + log.Println("Linked token is not elevated") + return + } } + runToken = elevatedToken + } else { + runToken = userToken } - defer elevatedToken.Close() + defer runToken.Close() userToken = 0 first := true for { @@ -186,7 +209,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest log.Printf("Starting UI process for user ā%s@%sā for session %d", username, domain, session) attr := &os.ProcAttr{ Sys: &syscall.SysProcAttr{ - Token: syscall.Token(elevatedToken), + Token: syscall.Token(runToken), }, Files: []*os.File{devNull, devNull, devNull}, Dir: userProfileDirectory, |