fix: verify active system session token setup
This commit is contained in:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user