问题描述
我正在尝试作为服务运行时获取登录用户的UPN。我能够以Username
格式获得DOMAIN\username
个已登录用户的信息,以及该用户的SessionID
和许多其他信息。
要获取UPN,我尝试通过获取访问令牌并使用此目标令牌运行whoami /upn
命令来模拟用户。当该服务直接执行此操作时效果很好,但是当该服务的子进程执行此操作时,它不起作用。
这是获取已登录用户的UPN的示例。实际上,我不能简单地获取当前用户的UPN,因为该应用程序正在作为服务运行
import (
"errors"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"unsafe"
winapi "github.com/kumako/go-win64api"
"golang.org/x/sys/windows"
"qohash.com/qostodian-agent/internal/logging"
)
var (
modwtsapi32 *windows.LazyDLL = windows.NewLazySystemDLL("wtsapi32.dll")
modadvapi32 *windows.LazyDLL = windows.NewLazySystemDLL("advapi32.dll")
procWTSQueryUserToken *windows.LazyProc = modwtsapi32.NewProc("WTSQueryUserToken")
procDuplicatetokenEx *windows.LazyProc = modadvapi32.NewProc("DuplicatetokenEx")
)
func GetUserSessions() ([]User,error) {
var u []User
users,err := winapi.ListLoggedInUsers()
if err != nil {
return u,err
}
for _,user := range users {
var upn string
var err error
// UPN Translation doesn't work -> try to impersonate the session and run whoami command
upn,err= getUpnForLoggedUser(user.SessionID)
if err!= nil {
logging.Debugf("Could not get UPN for user %v: \n\t - First attempt: %v \n\t ",user.FullUser(),err)
} else {
logging.Debugf("User UPN: %v",upn)
}
u = append(u,User{
Username: user.Username,Domain: user.Domain,Upn: upn,})
}
return u,nil
}
func getUpnForLoggedUser(sessionID uint32) (string,error) {
userToken,err := duplicateUserTokenFromSessionID(windows.Handle(sessionID))
if err != nil {
return "",fmt.Errorf("get duplicate user token for current user session: %s",err)
}
winPath,ok := os.LookupEnv("SystemRoot")
if !ok {
return "",errors.New("Cannot obtain SystemRoot environment variable")
}
cmd := exec.Command(fmt.Sprintf("%s\\system32\\whoami.exe",winPath),"/upn")
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: true,Token: userToken,}
out,err := cmd.CombinedOutput()
if err != nil {
return "",err
}
userToken.Close()
return strings.Trimspace(string(out)),nil
}
func duplicateUserTokenFromSessionID(sessionId windows.Handle) (syscall.Token,error) {
var (
impersonationToken windows.Handle = 0
userToken syscall.Token = 0
)
if returnCode,_,err := procWTSQueryUserToken.Call(uintptr(sessionId),uintptr(unsafe.Pointer(&impersonationToken))); returnCode == 0 {
return 0xFFFFFFFF,fmt.Errorf("call native WTSQueryUserToken: %s",err)
}
if returnCode,err := procDuplicatetokenEx.Call(uintptr(impersonationToken),uintptr(windows.SecurityImpersonation),uintptr(windows.TokenPrimary),uintptr(unsafe.Pointer(&userToken))); returnCode == 0 {
return 0xFFFFFFFF,fmt.Errorf("call native DuplicatetokenEx: %s",err)
}
if err := windows.CloseHandle(impersonationToken); err != nil {
return 0xFFFFFFFF,fmt.Errorf("close windows handle used for token duplication: %s",err)
}
return userToken,nil
}
当我的主要服务呼叫GetUserSessions
时,它可以工作并返回具有已登录UPN的用户。
如果此主服务产生一个子进程,则UPN始终为空。调用whoami
时,应用程序将获得fork/exec C:\WINDOWS\system32\whoami.exe: Access is denied
。
我的问题是:
谢谢!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)