Skip to content

Commit

Permalink
Merge pull request #22 from BishopFox/execute-assembly
Browse files Browse the repository at this point in the history
Execute assembly
  • Loading branch information
rkervella committed Feb 21, 2019
2 parents 80603d7 + 9a76320 commit 16b6e40
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 51 deletions.
59 changes: 59 additions & 0 deletions client/command/execute_assembly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package command

import (
"fmt"
"io/ioutil"

consts "sliver/client/constants"
"sliver/client/spin"
pb "sliver/protobuf/client"
sliverpb "sliver/protobuf/sliver"

"github.com/desertbit/grumble"
"github.com/golang/protobuf/proto"
)

func executeAssembly(ctx *grumble.Context, rpc RPCServer) {
if ActiveSliver.Sliver == nil {
fmt.Printf(Warn + "Please select an active sliver via `use`\n")
return
}

if len(ctx.Args) < 1 {
fmt.Printf(Warn + "Please provide valid arguments.\n")
return
}
assemblyBytes, err := ioutil.ReadFile(ctx.Args[0])
if err != nil {
fmt.Printf(Warn+"%s", err.Error())
return
}

assemblyArgs := ""
if len(ctx.Args) == 2 {
assemblyArgs = ctx.Args[1]
}

ctrl := make(chan bool)
go spin.Until("Executing assembly ...", ctrl)
data, _ := proto.Marshal(&sliverpb.ExecuteAssemblyReq{
SliverID: ActiveSliver.Sliver.ID,
Timeout: int32(5),
Arguments: assemblyArgs,
Assembly: assemblyBytes,
HostingDll: []byte{},
})

resp := rpc(&pb.Envelope{
Data: data,
Type: consts.ExecuteAssemblyStr,
}, defaultTimeout)
ctrl <- true
execResp := &sliverpb.ExecuteAssembly{}
proto.Unmarshal(resp.Data, execResp)
if execResp.Error != "" {
fmt.Printf(Warn+"%s", execResp.Error)
return
}
fmt.Printf(Info+"Assembly output:\n%s", execResp.Output)
}
12 changes: 12 additions & 0 deletions client/command/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,16 @@ func Init(app *grumble.App, rpc RPCServer) {
},
})

app.AddCommand(&grumble.Command{
Name: consts.ExecuteAssemblyStr,
Help: "Load and executes a .NET assembly in a child process",
LongHelp: help.GetHelpFor(consts.ExecuteAssemblyStr),
AllowArgs: true,
Run: func(ctx *grumble.Context) error {
fmt.Println()
executeAssembly(ctx, rpc)
fmt.Println()
return nil
},
})
}
19 changes: 10 additions & 9 deletions client/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ const (
GetGIDStr = "getgid"
WhoamiStr = "whoami"

LsStr = "ls"
RmStr = "rm"
MkdirStr = "mkdir"
CdStr = "cd"
PwdStr = "pwd"
CatStr = "cat"
DownloadStr = "download"
UploadStr = "upload"
ProcdumpStr = "procdump"
LsStr = "ls"
RmStr = "rm"
MkdirStr = "mkdir"
CdStr = "cd"
PwdStr = "pwd"
CatStr = "cat"
DownloadStr = "download"
UploadStr = "upload"
ProcdumpStr = "procdump"
ExecuteAssemblyStr = "execute-assembly"
)
30 changes: 17 additions & 13 deletions client/help/console-help.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,20 @@ var (
consts.UseStr: useHelp,
consts.GenerateStr: generateHelp,

consts.MsfStr: msfHelp,
consts.InjectStr: injectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.CatStr: catHelp,
consts.DownloadStr: downloadHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ProcdumpStr: procdumpHelp,
consts.MsfStr: msfHelp,
consts.InjectStr: injectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.CatStr: catHelp,
consts.DownloadStr: downloadHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ProcdumpStr: procdumpHelp,
consts.ExecuteAssemblyStr: executeAssemblyHelp,
}

jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
Expand Down Expand Up @@ -107,6 +108,9 @@ var (

procdumpHelp = `[[.Bold]]Command:[[.Normal]] procdump <pid>
[[.Bold]]About:[[.Normal]] Dumps the process memory given a process identifier (pid)`

executeAssemblyHelp = `[[.Bold]]Command:[[.Normal]] execute-assembly <path to assembly> [arguments]
[[.Bold]]About:[[.Normal]] Executes the .NET assembly in a child process.`
)

// GetHelpFor - Get help string for a command
Expand Down
4 changes: 4 additions & 0 deletions protobuf/sliver/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ const (
MsgProcessDumpReq
// MsgProcessDump - Dump of process)
MsgProcessDump
// MsgExecuteAssemblyReq - Request to load and execute a .NET assembly
MsgExecuteAssemblyReq
// MsgExecuteAssembly - Output of the assembly execution
MsgExecuteAssembly
)
13 changes: 13 additions & 0 deletions protobuf/sliver/sliver.proto
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,19 @@ message ProcessDump {
string err = 2;
}

message ExecuteAssemblyReq {
bytes hostingDll = 1;
bytes assembly = 2;
string arguments = 3;
int32 Timeout = 8;
int32 SliverID = 9;
}

message ExecuteAssembly {
string output = 1;
string error = 2;
}

// DNS Specific messages
message DNSSessionInit {
bytes key = 1;
Expand Down
23 changes: 23 additions & 0 deletions server/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,20 @@ func GetRootAppDir() string {
return dir
}

// GetDataDir - Returns the full path to the data directory
func GetDataDir() string {
dir := GetRootAppDir() + "/data"
return dir
}

// Setup - Extract or create local assets
// TODO: Add some type of version awareness
func Setup() {
appDir := GetRootAppDir()
SetupCerts(appDir)
setupGo(appDir)
setupCodenames(appDir)
SetupDataPath(appDir)
}

// SetupCerts - Creates directories for certs
Expand Down Expand Up @@ -131,6 +138,22 @@ func SetupGoPath(goPathSrc string) error {
return nil
}

// SetupDataPath - Sets the data directory up
func SetupDataPath(appDir string) error {
dataDir := appDir + "/data"
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
log.Printf("Creating data directory: %s", dataDir)
os.MkdirAll(dataDir, os.ModePerm)
}
hostingDll, err := assetsBox.Find("HostingCLRx64.dll")
if err != nil {
log.Printf("failed to find the dll")
return err
}
err = ioutil.WriteFile(dataDir+"/HostingCLRx64.dll", hostingDll, 0644)
return err
}

func unzipGoDependency(fileName string, targetPath string, assetsBox packr.Box) error {
log.Printf("Unpacking go dependency %s -> %s", fileName, targetPath)
appDir := GetRootAppDir()
Expand Down
32 changes: 32 additions & 0 deletions server/rpc/rpc-sliver.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"path"
pb "sliver/protobuf/client"
"sliver/server/assets"
"sliver/server/core"
"sliver/server/generate"
"time"
Expand Down Expand Up @@ -134,3 +135,34 @@ func rpcProcdump(req []byte, resp RPCResponse) {
data, err = sliver.Request(sliverpb.MsgProcessDumpReq, timeout, data)
resp(data, err)
}

func rpcExecuteAssembly(req []byte, resp RPCResponse) {
execReq := &sliverpb.ExecuteAssemblyReq{}
err := proto.Unmarshal(req, execReq)
if err != nil {
resp([]byte{}, err)
return
}
sliver := (*core.Hive.Slivers)[int(execReq.SliverID)]
if sliver == nil {
resp([]byte{}, err)
return
}
hostingDllPath := assets.GetDataDir() + "/HostingCLRx64.dll"
hostingDllBytes, err := ioutil.ReadFile(hostingDllPath)
if err != nil {
resp([]byte{}, err)
return
}
data, _ := proto.Marshal(&sliverpb.ExecuteAssemblyReq{
Assembly: execReq.Assembly,
HostingDll: hostingDllBytes,
Arguments: execReq.Arguments,
Timeout: execReq.Timeout,
SliverID: execReq.SliverID,
})
timeout := time.Duration(execReq.Timeout) * time.Second
data, err = sliver.Request(sliverpb.MsgExecuteAssemblyReq, timeout, data)
resp(data, err)

}
15 changes: 8 additions & 7 deletions server/rpc/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ var (
consts.PsStr: rpcPs,
consts.ProcdumpStr: rpcProcdump,

consts.LsStr: rpcLs,
consts.RmStr: rpcRm,
consts.MkdirStr: rpcMkdir,
consts.CdStr: rpcCd,
consts.PwdStr: rpcPwd,
consts.DownloadStr: rpcDownload,
consts.UploadStr: rpcUpload,
consts.LsStr: rpcLs,
consts.RmStr: rpcRm,
consts.MkdirStr: rpcMkdir,
consts.CdStr: rpcCd,
consts.PwdStr: rpcPwd,
consts.DownloadStr: rpcDownload,
consts.UploadStr: rpcUpload,
consts.ExecuteAssemblyStr: rpcExecuteAssembly,
}
)

Expand Down
30 changes: 27 additions & 3 deletions sliver/handlers_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import (
var (
windowsHandlers = map[uint32]RPCHandler{
// Windows Only
pb.MsgTask: taskHandler,
pb.MsgRemoteTask: remoteTaskHandler,
pb.MsgProcessDumpReq: dumpHandler,
pb.MsgTask: taskHandler,
pb.MsgRemoteTask: remoteTaskHandler,
pb.MsgProcessDumpReq: dumpHandler,
pb.MsgExecuteAssemblyReq: executeAssemblyHandler,

// Generic
pb.MsgPsListReq: psHandler,
Expand Down Expand Up @@ -63,3 +64,26 @@ func remoteTaskHandler(data []byte, resp RPCResponse) {
err = taskrunner.RemoteTask(int(remoteTask.Pid), remoteTask.Data)
resp([]byte{}, err)
}

func executeAssemblyHandler(data []byte, resp RPCResponse) {
execReq := &pb.ExecuteAssemblyReq{}
err := proto.Unmarshal(data, execReq)
if err != nil {
// {{if .Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
output, err := taskrunner.ExecuteAssembly(execReq.HostingDll, execReq.Assembly, execReq.Arguments, execReq.Timeout)
strErr := ""
if err != nil {
strErr = err.Error()
}
execResp := &pb.ExecuteAssembly{
Output: output,
Error: strErr,
}
data, err = proto.Marshal(execResp)
resp(data, err)

}

0 comments on commit 16b6e40

Please sign in to comment.