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
|
return 0, supervisor.EffectiveIdentity{}, err
|
||||||
}
|
}
|
||||||
defer source.Close()
|
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
|
var target winapi.Token
|
||||||
if err := winapi.DuplicateTokenEx(source, winapi.TOKEN_ALL_ACCESS, nil, winapi.SecurityImpersonation, winapi.TokenPrimary, &target); err != nil {
|
if err := winapi.DuplicateTokenEx(source, winapi.TOKEN_ALL_ACCESS, nil, winapi.SecurityImpersonation, winapi.TokenPrimary, &target); err != nil {
|
||||||
return 0, supervisor.EffectiveIdentity{}, err
|
return 0, supervisor.EffectiveIdentity{}, err
|
||||||
@@ -658,6 +667,16 @@ func duplicateServiceTokenForSession(sessionID uint32) (winapi.Token, supervisor
|
|||||||
_ = target.Close()
|
_ = target.Close()
|
||||||
return 0, supervisor.EffectiveIdentity{}, err
|
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()
|
user, err := target.GetTokenUser()
|
||||||
if err != nil || user.User.Sid == nil || user.User.Sid.String() != securitySystemRID {
|
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
|
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) {
|
func logonLocalService() (winapi.Token, error) {
|
||||||
account, _ := syscall.UTF16PtrFromString("LocalService")
|
account, _ := syscall.UTF16PtrFromString("LocalService")
|
||||||
domainName, _ := syscall.UTF16PtrFromString("NT AUTHORITY")
|
domainName, _ := syscall.UTF16PtrFromString("NT AUTHORITY")
|
||||||
|
|||||||
Reference in New Issue
Block a user