From 6c85c8e03915ce345c49d942e8a1ad7255effabb Mon Sep 17 00:00:00 2001 From: cabbage Date: Sun, 6 Sep 2026 13:58:00 +0000 Subject: [PATCH] fix: verify active system session token setup --- .../supervisor/windows/native_windows.go | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/internal/client/supervisor/windows/native_windows.go b/internal/client/supervisor/windows/native_windows.go index 0a1fac4..9f61a04 100644 --- a/internal/client/supervisor/windows/native_windows.go +++ b/internal/client/supervisor/windows/native_windows.go @@ -649,6 +649,15 @@ func duplicateServiceTokenForSession(sessionID uint32) (winapi.Token, supervisor return 0, supervisor.EffectiveIdentity{}, err } defer source.Close() + var restorePrivilege func() + if sessionID != 0 { + var err error + restorePrivilege, err = enableTokenPrivilege(source, "SeTcbPrivilege") + if err != nil { + return 0, supervisor.EffectiveIdentity{}, fmt.Errorf("enable SeTcbPrivilege for active session token: %w", err) + } + defer restorePrivilege() + } var target winapi.Token if err := winapi.DuplicateTokenEx(source, winapi.TOKEN_ALL_ACCESS, nil, winapi.SecurityImpersonation, winapi.TokenPrimary, &target); err != nil { return 0, supervisor.EffectiveIdentity{}, err @@ -658,6 +667,16 @@ func duplicateServiceTokenForSession(sessionID uint32) (winapi.Token, supervisor _ = target.Close() return 0, supervisor.EffectiveIdentity{}, err } + var actualSession uint32 + var returned uint32 + if err := winapi.GetTokenInformation(target, winapi.TokenSessionId, (*byte)(unsafe.Pointer(&actualSession)), uint32(unsafe.Sizeof(actualSession)), &returned); err != nil { + _ = target.Close() + return 0, supervisor.EffectiveIdentity{}, fmt.Errorf("verify active SYSTEM token session: %w", err) + } + if returned != uint32(unsafe.Sizeof(actualSession)) || actualSession != sessionID { + _ = target.Close() + return 0, supervisor.EffectiveIdentity{}, errors.New("active SYSTEM token session did not read back as requested") + } } user, err := target.GetTokenUser() if err != nil || user.User.Sid == nil || user.User.Sid.String() != securitySystemRID { @@ -670,6 +689,39 @@ func duplicateServiceTokenForSession(sessionID uint32) (winapi.Token, supervisor return target, supervisor.EffectiveIdentity{Context: string(ContextLocalSystem), SessionID: sessionID, UserSID: user.User.Sid.String(), Elevated: true, Integrity: "system"}, nil } +// enableTokenPrivilege enables one privilege only for the short operation +// that needs it and returns a best-effort restoration closure. Windows may +// report ERROR_NOT_ALL_ASSIGNED even when AdjustTokenPrivileges itself +// succeeds; treat that as a hard capability failure rather than silently +// creating a Session-0 token for an active-session request. +func enableTokenPrivilege(token winapi.Token, name string) (func(), error) { + privilegeName, err := winapi.UTF16PtrFromString(name) + if err != nil { + return nil, err + } + var luid winapi.LUID + if err := winapi.LookupPrivilegeValue(nil, privilegeName, &luid); err != nil { + return nil, err + } + state := winapi.Tokenprivileges{PrivilegeCount: 1} + state.Privileges[0] = winapi.LUIDAndAttributes{Luid: luid, Attributes: winapi.SE_PRIVILEGE_ENABLED} + var previous winapi.Tokenprivileges + var returned uint32 + if err := winapi.AdjustTokenPrivileges(token, false, &state, uint32(unsafe.Sizeof(state)), &previous, &returned); err != nil { + return nil, err + } + if lastErr := winapi.GetLastError(); lastErr != nil && !errors.Is(lastErr, syscall.Errno(0)) { + return nil, lastErr + } + restore := func() { + if returned == 0 { + return + } + _ = winapi.AdjustTokenPrivileges(token, false, &previous, uint32(unsafe.Sizeof(previous)), nil, nil) + } + return restore, nil +} + func logonLocalService() (winapi.Token, error) { account, _ := syscall.UTF16PtrFromString("LocalService") domainName, _ := syscall.UTF16PtrFromString("NT AUTHORITY")