Compare commits

...
27 changed files with 3372 additions and 2430 deletions

No files matched your search

+15
View File
@@ -27,6 +27,7 @@ func Commands(con *console.SliverClient) []*cobra.Command {
flags.Bind("", false, executeCmd, func(f *pflag.FlagSet) {
f.BoolP("token", "T", false, "execute command with current token (Windows only)")
f.BoolP("output", "o", true, "capture command output")
f.Bool("background", false, "start the process in the background and track it")
f.BoolP("save", "s", false, "save output to a file")
f.BoolP("loot", "X", false, "save output as loot")
f.BoolP("ignore-stderr", "S", false, "don't print STDERR output")
@@ -45,6 +46,20 @@ func Commands(con *console.SliverClient) []*cobra.Command {
carapace.Gen(executeCmd).PositionalCompletion(carapace.ActionValues().Usage("command to execute (required)"))
carapace.Gen(executeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to the command (optional)"))
executeChildrenCmd := &cobra.Command{
Use: consts.ExecuteChildrenStr,
Short: "List tracked background execute child processes",
Long: help.GetHelpFor([]string{consts.ExecuteStr, consts.ExecuteChildrenStr}),
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
ExecuteChildrenCmd(cmd, con, args)
},
}
flags.Bind("", false, executeChildrenCmd, func(f *pflag.FlagSet) {
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
executeCmd.AddCommand(executeChildrenCmd)
executeAssemblyCmd := &cobra.Command{
Use: consts.ExecuteAssemblyStr,
Short: "Loads and executes a .NET assembly in a child process (Windows Only)",
+106
View File
@@ -0,0 +1,106 @@
package exec
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"sort"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"google.golang.org/protobuf/proto"
)
// ExecuteChildrenCmd - List tracked background execute child processes on the implant.
func ExecuteChildrenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
ctrl := make(chan bool)
con.SpinUntil("Querying execute children ...", ctrl)
execChildren, err := con.Rpc.ExecuteChildren(context.Background(), &sliverpb.ExecuteChildrenReq{
Request: con.ActiveTarget.Request(cmd),
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if execChildren.Response != nil && execChildren.Response.Async {
con.AddBeaconCallback(execChildren.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, execChildren)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecuteChildren(execChildren, con)
})
con.PrintAsyncResponse(execChildren.Response)
return
}
PrintExecuteChildren(execChildren, con)
}
// PrintExecuteChildren - Render execute children output.
func PrintExecuteChildren(execChildren *sliverpb.ExecuteChildren, con *console.SliverClient) {
if execChildren == nil || len(execChildren.Children) == 0 {
con.PrintInfof("No tracked background execute children\n")
return
}
children := append([]*sliverpb.ExecuteChild(nil), execChildren.Children...)
sort.Slice(children, func(i, j int) bool {
return children[i].StartTime < children[j].StartTime
})
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{"pid", "state", "exit", "started", "command", "stdout", "stderr"})
for _, child := range children {
state := "running"
exitCode := "-"
if child.Exited {
state = "exited"
exitCode = fmt.Sprintf("%d", child.ExitCode)
}
started := "-"
if child.StartTime != 0 {
started = time.Unix(child.StartTime, 0).Local().Format("2006-01-02 15:04:05")
}
command := strings.TrimSpace(fmt.Sprintf("%s %s", child.Path, strings.Join(child.Args, " ")))
tw.AppendRow(table.Row{child.Pid, state, exitCode, started, command, child.Stdout, child.Stderr})
}
con.Printf("%s\n", tw.Render())
}
+26 -6
View File
@@ -44,6 +44,7 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
token, _ := cmd.Flags().GetBool("token")
hidden, _ := cmd.Flags().GetBool("hidden")
output, _ := cmd.Flags().GetBool("output")
background, _ := cmd.Flags().GetBool("background")
stdout, _ := cmd.Flags().GetString("stdout")
stderr, _ := cmd.Flags().GetString("stderr")
saveLoot, _ := cmd.Flags().GetBool("loot")
@@ -58,10 +59,15 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
}
hostName := getHostname(session, beacon)
// If the user wants to loot or save the output, we have to capture it regardless of if they specified -o
captureOutput := output || saveLoot || saveOutput
if background && (saveLoot || saveOutput) {
con.PrintErrorf("The loot and save options are not supported with --background\n")
return
}
if output && beacon != nil {
// If the user wants to loot or save the output, we have to capture it regardless of if they specified -o
captureOutput := !background && (output || saveLoot || saveOutput)
if captureOutput && beacon != nil {
con.PrintWarnf("Using --output in beacon mode, if the command blocks the task will never complete\n\n")
}
@@ -84,6 +90,7 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
Path: cmdPath,
Args: args,
Output: captureOutput,
Background: background,
Stderr: stderr,
Stdout: stdout,
UseToken: token,
@@ -96,6 +103,7 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
Path: cmdPath,
Args: args,
Output: captureOutput,
Background: background,
Stderr: stderr,
Stdout: stdout,
EnvInheritance: envInheritance,
@@ -154,11 +162,23 @@ func PrintExecute(exec *sliverpb.Execute, cmd *cobra.Command, con *console.Slive
stderr, _ := cmd.Flags().GetString("stderr")
output, _ := cmd.Flags().GetBool("output")
background := false
if cmd.Flags().Lookup("background") != nil {
background, _ = cmd.Flags().GetBool("background")
}
if background {
// Background execution never returns inline output.
output = false
}
if !output {
if exec.Status == 0 {
con.PrintInfof("Command executed successfully\n")
if exec.Pid != 0 {
if background {
con.PrintInfof("Started background process (pid: %d)\n", exec.Pid)
return
}
con.PrintInfof("Started process (pid: %d)\n", exec.Pid)
} else {
con.PrintErrorf("Exit code %d\n", exec.Status)
con.PrintInfof("Process started\n")
}
return
}
+45 -38
View File
@@ -47,44 +47,45 @@ var (
consts.GenerateStr: generateHelp,
consts.StageListenerStr: stageListenerHelp,
consts.MsfStr: msfHelp,
consts.MsfInjectStr: msfInjectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.PwdStr: pwdHelp,
consts.CatStr: catHelp,
consts.EditStr: editHelp,
consts.HexEditStr: hexEditHelp,
consts.DownloadStr: downloadHelp,
consts.GrepStr: grepHelp,
consts.HeadStr: headHelp,
consts.TailStr: tailHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ChtimesStr: chtimesHelp,
consts.ProcdumpStr: procdumpHelp,
consts.ElevateStr: elevateHelp,
consts.RunAsStr: runAsHelp,
consts.ImpersonateStr: impersonateHelp,
consts.RevToSelfStr: revToSelfHelp,
consts.ExecuteStr: executeHelp,
consts.ExecuteAssemblyStr: executeAssemblyHelp,
consts.ExecuteShellcodeStr: executeShellcodeHelp,
consts.MigrateStr: migrateHelp,
consts.SideloadStr: sideloadHelp,
consts.TerminateStr: terminateHelp,
consts.AliasesStr: loadAliasHelp,
consts.PsExecStr: psExecHelp,
consts.BackdoorStr: backdoorHelp,
consts.SpawnDllStr: spawnDllHelp,
consts.MountStr: mountHelp,
consts.ShikataGaNai: shikataGaNaiHelp,
consts.ShellcodeEncodersStr: shellcodeEncodersHelp,
consts.ShellcodeEncodersStr + sep + "encode": shellcodeEncodersEncodeHelp,
consts.MsfStr: msfHelp,
consts.MsfInjectStr: msfInjectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.PwdStr: pwdHelp,
consts.CatStr: catHelp,
consts.EditStr: editHelp,
consts.HexEditStr: hexEditHelp,
consts.DownloadStr: downloadHelp,
consts.GrepStr: grepHelp,
consts.HeadStr: headHelp,
consts.TailStr: tailHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ChtimesStr: chtimesHelp,
consts.ProcdumpStr: procdumpHelp,
consts.ElevateStr: elevateHelp,
consts.RunAsStr: runAsHelp,
consts.ImpersonateStr: impersonateHelp,
consts.RevToSelfStr: revToSelfHelp,
consts.ExecuteStr: executeHelp,
consts.ExecuteStr + sep + consts.ExecuteChildrenStr: executeChildrenHelp,
consts.ExecuteAssemblyStr: executeAssemblyHelp,
consts.ExecuteShellcodeStr: executeShellcodeHelp,
consts.MigrateStr: migrateHelp,
consts.SideloadStr: sideloadHelp,
consts.TerminateStr: terminateHelp,
consts.AliasesStr: loadAliasHelp,
consts.PsExecStr: psExecHelp,
consts.BackdoorStr: backdoorHelp,
consts.SpawnDllStr: spawnDllHelp,
consts.MountStr: mountHelp,
consts.ShikataGaNai: shikataGaNaiHelp,
consts.ShellcodeEncodersStr: shellcodeEncodersHelp,
consts.ShellcodeEncodersStr + sep + "encode": shellcodeEncodersEncodeHelp,
consts.WebsitesStr: websitesHelp,
consts.ScreenshotStr: screenshotHelp,
@@ -135,6 +136,7 @@ var (
[[.Bold]]About:[[.Normal]] Execute a program on the remote system with optional arguments, note the subprocess
arguments are be separated from the sliver 'execute' arguments with '--'
Use [[.Bold]]--background[[.Normal]] to start the process without waiting for output (use [[.Bold]]--stdout[[.Normal]]/[[.Bold]]--stderr[[.Normal]] to redirect).
[[.Bold]]Example:[[.Normal]]
execute /bin/bash --env FOO=1 -- -c env
@@ -145,6 +147,11 @@ FOO=1
PWD=/Users/moloch/git/sliver
SHLVL=1
_=/usr/bin/env
`
executeChildrenHelp = `[[.Bold]]Command:[[.Normal]] execute children
[[.Bold]]About:[[.Normal]] List tracked background child processes started with [[.Bold]]execute --background[[.Normal]].
`
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
+13 -3
View File
@@ -285,11 +285,12 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverClient) {
}
f := pflag.NewFlagSet(constants.ExecuteStr, pflag.ContinueOnError)
f.BoolP("output", "o", true, "capture command output")
f.BoolP("output", "o", execReq.Output, "capture command output")
f.Bool("background", execReq.Background, "start the process in the background and track it")
f.BoolP("loot", "X", false, "save output as loot")
f.BoolP("ignore-stderr", "S", false, "don't print STDERR output")
f.StringP("stdout", "O", "", "remote path to redirect STDOUT to")
f.StringP("stderr", "E", "", "remote path to redirect STDERR to")
f.StringP("stdout", "O", execReq.Stdout, "remote path to redirect STDOUT to")
f.StringP("stderr", "E", execReq.Stderr, "remote path to redirect STDERR to")
execCmd := &cobra.Command{Use: constants.ExecuteStr}
execCmd.Flags().AddFlagSet(f)
@@ -297,6 +298,15 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverClient) {
exec.PrintExecute(execResult, execCmd, con)
case sliverpb.MsgExecuteChildrenReq:
execChildren := &sliverpb.ExecuteChildren{}
err := proto.Unmarshal(task.Response, execChildren)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
exec.PrintExecuteChildren(execChildren, con)
case sliverpb.MsgSideloadReq:
sideload := &sliverpb.Sideload{}
err := proto.Unmarshal(task.Response, sideload)
+3 -2
View File
@@ -208,8 +208,9 @@ const (
GetGIDStr = "getgid"
WhoamiStr = "whoami"
ShellStr = "shell"
ExecuteStr = "execute"
ShellStr = "shell"
ExecuteStr = "execute"
ExecuteChildrenStr = "children"
LsStr = "ls"
MvStr = "mv"
+2 -1
View File
@@ -40,7 +40,8 @@ func ArmoryInstallForm(options []ArmoryInstallOption) (*ArmoryInstallFormResult,
Title("Select packages or bundles to install").
Description("Use space to select and enter to install.").
Options(selectOptions...).
Height(listHeight(len(selectOptions))).
// huh.MultiSelect Height includes title/description, so add 2 lines for them.
Height(listHeight(len(selectOptions)) + 2).
Value(&result.SelectedNames)
form := huh.NewForm(huh.NewGroup(field))
+2 -1
View File
@@ -39,7 +39,8 @@ func ArmoryUpdateForm(options []ArmoryUpdateOption) (*ArmoryUpdateFormResult, er
Title("Select updates to apply").
Description("Use space to select and enter to apply.").
Options(selectOptions...).
Height(listHeight(len(selectOptions))).
// huh.MultiSelect Height includes title/description, so add 2 lines for them.
Height(listHeight(len(selectOptions)) + 2).
Value(&result.SelectedIDs)
form := huh.NewForm(huh.NewGroup(field))
+8 -7
View File
@@ -2,13 +2,14 @@ package forms
import (
"errors"
"slices"
"strings"
"github.com/charmbracelet/huh"
"golang.org/x/term"
)
const defaultSelectHeight = 10
const defaultSelectHeight = 5
func getTerminalWidth() int {
// Try to get actual terminal width
@@ -93,7 +94,8 @@ func MultiSelect(title string, options []string, value *[]string) error {
field := huh.NewMultiSelect[string]().
Title(title).
Options(makeStringOptions(options)...).
Height(listHeight(len(options))).
// huh.Select/MultiSelect Height includes title/description, so add 1 for the title line.
Height(listHeight(len(options)) + 1).
Value(value)
form := huh.NewForm(huh.NewGroup(field)).WithWidth(getTerminalWidth())
@@ -115,7 +117,8 @@ func selectPrompt(title string, options []string, value *string, required bool)
field := huh.NewSelect[string]().
Title(title).
Options(makeStringOptions(options)...).
Height(listHeight(len(options))).
// huh.Select Height includes title/description, so add 1 for the title line.
Height(listHeight(len(options)) + 1).
Value(value)
if required {
@@ -147,10 +150,8 @@ func ensureSelectedValue(options []string, value *string) {
*value = options[0]
return
}
for _, option := range options {
if option == *value {
return
}
if slices.Contains(options, *value) {
return
}
*value = options[0]
}
+204
View File
@@ -0,0 +1,204 @@
package handlers
import (
"os"
"os/exec"
"sort"
"sync"
"time"
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
const (
maxTrackedExecuteChildren = 256
)
type executeChildEntry struct {
PID int32
Path string
Args []string
Stdout string
Stderr string
StartTime int64
Exited bool
ExitCode int32
ExitTime int64
Error string
cmd *exec.Cmd
}
var (
executeChildrenMu sync.RWMutex
trackedExecuteChildren = map[int32]*executeChildEntry{}
)
func trimTrackedExecuteChildrenLocked() {
if len(trackedExecuteChildren) <= maxTrackedExecuteChildren {
return
}
// Prefer trimming completed entries first, oldest exit time first.
exited := make([]*executeChildEntry, 0, len(trackedExecuteChildren))
for _, entry := range trackedExecuteChildren {
if entry.Exited {
exited = append(exited, entry)
}
}
sort.Slice(exited, func(i, j int) bool {
return exited[i].ExitTime < exited[j].ExitTime
})
for len(trackedExecuteChildren) > maxTrackedExecuteChildren && 0 < len(exited) {
delete(trackedExecuteChildren, exited[0].PID)
exited = exited[1:]
}
}
func startExecuteChild(cmd *exec.Cmd, track bool, path string, args []string, stdoutPath string, stderrPath string) (int32, error) {
var (
stdoutFile *os.File
stderrFile *os.File
err error
)
startTime := time.Now().Unix()
if stdoutPath != "" {
stdoutFile, err = os.Create(stdoutPath)
if err != nil {
return 0, err
}
cmd.Stdout = stdoutFile
}
if stderrPath != "" {
stderrFile, err = os.Create(stderrPath)
if err != nil {
if stdoutFile != nil {
stdoutFile.Close()
}
return 0, err
}
cmd.Stderr = stderrFile
}
err = cmd.Start()
if err != nil {
if stdoutFile != nil {
stdoutFile.Close()
}
if stderrFile != nil {
stderrFile.Close()
}
return 0, err
}
var pid int32
if cmd.Process != nil {
pid = int32(cmd.Process.Pid)
}
if track && pid != 0 {
entry := &executeChildEntry{
PID: pid,
Path: path,
Args: append([]string(nil), args...),
Stdout: stdoutPath,
Stderr: stderrPath,
StartTime: startTime,
cmd: cmd,
}
executeChildrenMu.Lock()
trackedExecuteChildren[pid] = entry
trimTrackedExecuteChildrenLocked()
executeChildrenMu.Unlock()
}
go func(pid int32, cmd *exec.Cmd, stdoutFile *os.File, stderrFile *os.File, track bool) {
waitErr := cmd.Wait()
exitCode := int32(0)
waitErrStr := ""
if waitErr != nil {
if exitErr, ok := waitErr.(*exec.ExitError); ok {
exitCode = int32(exitErr.ExitCode())
} else {
exitCode = -1
waitErrStr = waitErr.Error()
}
}
if track && pid != 0 {
executeChildrenMu.Lock()
entry := trackedExecuteChildren[pid]
if entry != nil {
entry.Exited = true
entry.ExitCode = exitCode
entry.ExitTime = time.Now().Unix()
entry.Error = waitErrStr
entry.cmd = nil
}
executeChildrenMu.Unlock()
}
if stdoutFile != nil {
stdoutFile.Close()
}
if stderrFile != nil {
stderrFile.Close()
}
}(pid, cmd, stdoutFile, stderrFile, track)
return pid, nil
}
func snapshotExecuteChildren() []*sliverpb.ExecuteChild {
executeChildrenMu.RLock()
children := make([]*sliverpb.ExecuteChild, 0, len(trackedExecuteChildren))
for _, entry := range trackedExecuteChildren {
children = append(children, &sliverpb.ExecuteChild{
Pid: entry.PID,
Path: entry.Path,
Args: append([]string(nil), entry.Args...),
StartTime: entry.StartTime,
Exited: entry.Exited,
ExitCode: entry.ExitCode,
ExitTime: entry.ExitTime,
Stdout: entry.Stdout,
Stderr: entry.Stderr,
Error: entry.Error,
})
}
executeChildrenMu.RUnlock()
sort.Slice(children, func(i, j int) bool {
return children[i].StartTime < children[j].StartTime
})
return children
}
func executeChildrenHandler(data []byte, resp RPCResponse) {
req := &sliverpb.ExecuteChildrenReq{}
err := proto.Unmarshal(data, req)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
execChildren := &sliverpb.ExecuteChildren{
Children: snapshotExecuteChildren(),
Response: &commonpb.Response{},
}
data, err = proto.Marshal(execChildren)
resp(data, err)
}
+6 -11
View File
@@ -1181,7 +1181,7 @@ func executeHandler(data []byte, resp RPCResponse) {
}
}
if execReq.Output {
if execReq.Output && !execReq.Background {
stdOutBuff := new(bytes.Buffer)
stdErrBuff := new(bytes.Buffer)
stdErr = stdErrBuff
@@ -1242,19 +1242,14 @@ func executeHandler(data []byte, resp RPCResponse) {
execResp.Pid = uint32(cmd.Process.Pid)
}
} else {
err = cmd.Start()
if err != nil {
pid, startErr := startExecuteChild(cmd, execReq.Background, exePath, execReq.Args, execReq.Stdout, execReq.Stderr)
if startErr != nil {
execResp.Response = &commonpb.Response{
Err: fmt.Sprintf("%s", err),
Err: fmt.Sprintf("%s", startErr),
}
}
go func() {
cmd.Wait()
}()
if cmd.Process != nil {
execResp.Pid = uint32(cmd.Process.Pid)
if pid != 0 {
execResp.Pid = uint32(pid)
}
}
data, err = proto.Marshal(execResp)
+20 -19
View File
@@ -33,25 +33,26 @@ import (
var (
darwinHandlers = map[uint32]RPCHandler{
pb.MsgPsReq: psHandler,
pb.MsgTerminateReq: terminateHandler,
pb.MsgPing: pingHandler,
pb.MsgLsReq: dirListHandler,
pb.MsgDownloadReq: downloadHandler,
pb.MsgUploadReq: uploadHandler,
pb.MsgCdReq: cdHandler,
pb.MsgPwdReq: pwdHandler,
pb.MsgRmReq: rmHandler,
pb.MsgMkdirReq: mkdirHandler,
pb.MsgMvReq: mvHandler,
pb.MsgCpReq: cpHandler,
pb.MsgIfconfigReq: ifconfigHandler,
pb.MsgExecuteReq: executeHandler,
pb.MsgEnvReq: getEnvHandler,
pb.MsgSetEnvReq: setEnvHandler,
pb.MsgUnsetEnvReq: unsetEnvHandler,
pb.MsgChtimesReq: chtimesHandler,
pb.MsgGrepReq: grepHandler,
pb.MsgPsReq: psHandler,
pb.MsgTerminateReq: terminateHandler,
pb.MsgPing: pingHandler,
pb.MsgLsReq: dirListHandler,
pb.MsgDownloadReq: downloadHandler,
pb.MsgUploadReq: uploadHandler,
pb.MsgCdReq: cdHandler,
pb.MsgPwdReq: pwdHandler,
pb.MsgRmReq: rmHandler,
pb.MsgMkdirReq: mkdirHandler,
pb.MsgMvReq: mvHandler,
pb.MsgCpReq: cpHandler,
pb.MsgIfconfigReq: ifconfigHandler,
pb.MsgExecuteReq: executeHandler,
pb.MsgExecuteChildrenReq: executeChildrenHandler,
pb.MsgEnvReq: getEnvHandler,
pb.MsgSetEnvReq: setEnvHandler,
pb.MsgUnsetEnvReq: unsetEnvHandler,
pb.MsgChtimesReq: chtimesHandler,
pb.MsgGrepReq: grepHandler,
pb.MsgScreenshotReq: screenshotHandler,
pb.MsgNetstatReq: netstatHandler,
+18 -17
View File
@@ -34,23 +34,24 @@ import (
var (
genericHandlers = map[uint32]RPCHandler{
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgChtimesReq: chtimesHandler,
sliverpb.MsgGrepReq: grepHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgExecuteChildrenReq: executeChildrenHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgChtimesReq: chtimesHandler,
sliverpb.MsgGrepReq: grepHandler,
// Wasm Extensions - Note that execution can be done via a tunnel handler
sliverpb.MsgRegisterWasmExtensionReq: registerWasmExtensionHandler,
+19 -18
View File
@@ -45,24 +45,25 @@ import (
var (
linuxHandlers = map[uint32]RPCHandler{
sliverpb.MsgPsReq: psHandler,
sliverpb.MsgTerminateReq: terminateHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgIfconfigReq: ifconfigLinuxHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgPsReq: psHandler,
sliverpb.MsgTerminateReq: terminateHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgIfconfigReq: ifconfigLinuxHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgExecuteChildrenReq: executeChildrenHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgScreenshotReq: screenshotHandler,
+26 -19
View File
@@ -96,21 +96,22 @@ var (
sliverpb.MsgMountReq: mountHandler,
// Generic
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
sliverpb.MsgChtimesReq: chtimesHandler,
sliverpb.MsgGrepReq: grepHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgCpReq: cpHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgExecuteChildrenReq: executeChildrenHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
sliverpb.MsgChtimesReq: chtimesHandler,
sliverpb.MsgGrepReq: grepHandler,
// Extensions
sliverpb.MsgRegisterExtensionReq: registerExtensionHandler,
@@ -386,7 +387,7 @@ func executeWindowsHandler(data []byte, resp RPCResponse) {
}
}
if execReq.Output {
if execReq.Output && !execReq.Background {
stdOutBuff := new(bytes.Buffer)
stdErrBuff := new(bytes.Buffer)
stdErr = stdErrBuff
@@ -443,13 +444,19 @@ func executeWindowsHandler(data []byte, resp RPCResponse) {
}
execResp.Stderr = stdErrBuff.Bytes()
execResp.Stdout = stdOutBuff.Bytes()
if cmd.Process != nil {
execResp.Pid = uint32(cmd.Process.Pid)
}
} else {
err = cmd.Start()
if err != nil {
pid, startErr := startExecuteChild(cmd, execReq.Background, exePath, execReq.Args, execReq.Stdout, execReq.Stderr)
if startErr != nil {
execResp.Response = &commonpb.Response{
Err: fmt.Sprintf("%s", err),
Err: fmt.Sprintf("%s", startErr),
}
}
if pid != 0 {
execResp.Pid = uint32(pid)
}
}
data, err = proto.Marshal(execResp)
resp(data, err)
+24 -1
View File
@@ -37,6 +37,8 @@ import (
// {{end}}
// {{if or .Config.IncludeMTLS .Config.IncludeWG}}
"errors"
"github.com/hashicorp/yamux"
// {{end}}
@@ -46,7 +48,6 @@ import (
// {{end}}
// {{if .Config.IncludeWG}}
"errors"
"net"
"github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
@@ -208,6 +209,9 @@ func mtlsBeacon(uri *url.URL) *Beacon {
if err != nil {
return err
}
if conn == nil {
return errors.New("[mtls] connect returned nil conn")
}
if _, err := conn.Write([]byte(mtls.YamuxPreface)); err != nil {
_ = conn.Close()
return err
@@ -217,21 +221,40 @@ func mtlsBeacon(uri *url.URL) *Beacon {
_ = conn.Close()
return err
}
if muxSession == nil {
_ = conn.Close()
return errors.New("[mtls] failed to create yamux session (nil)")
}
return nil
},
Recv: func() (*pb.Envelope, error) {
if muxSession == nil {
return nil, errors.New("[mtls] recv called with nil yamux session")
}
stream, err := muxSession.Accept()
if err != nil {
return nil, err
}
if isNilInterface(stream) {
return nil, errors.New("[mtls] accept returned nil stream")
}
defer stream.Close()
return mtls.ReadEnvelope(stream)
},
Send: func(envelope *pb.Envelope) error {
if envelope == nil {
return errors.New("[mtls] nil envelope")
}
if muxSession == nil {
return errors.New("[mtls] send called with nil yamux session")
}
stream, err := muxSession.Open()
if err != nil {
return err
}
if isNilInterface(stream) {
return errors.New("[mtls] open returned nil stream")
}
defer stream.Close()
return mtls.WriteEnvelope(stream, envelope)
},
+45 -11
View File
@@ -21,7 +21,6 @@ package mtls
// {{if .Config.IncludeMTLS}}
import (
"bytes"
"crypto/ed25519"
"crypto/sha256"
"crypto/tls"
@@ -30,6 +29,7 @@ import (
"errors"
"fmt"
"io"
"reflect"
"sync"
"time"
@@ -90,43 +90,77 @@ func mtlsEnvelopeSigningKey() (ed25519.PrivateKey, uint64, error) {
return envelopeSigningPriv, envelopeSigningKeyID, envelopeSigningErr
}
func isNilInterface(v any) bool {
if v == nil {
return true
}
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Interface, reflect.Slice:
return rv.IsNil()
default:
return false
}
}
func writeAll(w io.Writer, p []byte) error {
for len(p) > 0 {
n, err := w.Write(p)
if err != nil {
return err
}
if n <= 0 {
return io.ErrShortWrite
}
p = p[n:]
}
return nil
}
// WriteEnvelope - Writes a message to the TLS socket using length prefix framing
// which is a fancy way of saying we write the length of the message then the message
// e.g. [uint32 length|message] so the receiver can delimit messages properly
func WriteEnvelope(w io.Writer, envelope *pb.Envelope) error {
if envelope == nil {
return errors.New("[mtls] nil envelope")
}
if isNilInterface(w) {
return errors.New("[mtls] nil writer")
}
data, err := proto.Marshal(envelope)
if err != nil {
// {{if .Config.Debug}}
log.Print("Envelope marshaling error: ", err)
// {{end}}
return err
return fmt.Errorf("[mtls] marshal envelope: %w", err)
}
signingKey, keyID, err := mtlsEnvelopeSigningKey()
if err != nil {
return err
return fmt.Errorf("[mtls] envelope signing key: %w", err)
}
rawSigBuf := make([]byte, cryptography.RawSigSize)
binary.LittleEndian.PutUint16(rawSigBuf[:2], cryptography.EdDSA)
binary.LittleEndian.PutUint64(rawSigBuf[2:10], keyID)
copy(rawSigBuf[10:], ed25519.Sign(signingKey, data))
if _, werr := w.Write(rawSigBuf); werr != nil {
return werr
if werr := writeAll(w, rawSigBuf); werr != nil {
return fmt.Errorf("[mtls] write raw signature: %w", werr)
}
dataLengthBuf := new(bytes.Buffer)
binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data)))
if _, werr := w.Write(dataLengthBuf.Bytes()); werr != nil {
var dataLengthBuf [4]byte
binary.LittleEndian.PutUint32(dataLengthBuf[:], uint32(len(data)))
if werr := writeAll(w, dataLengthBuf[:]); werr != nil {
// {{if .Config.Debug}}
log.Print("Error writing data length: ", werr)
// {{end}}
return werr
return fmt.Errorf("[mtls] write data length: %w", werr)
}
if _, werr := w.Write(data); werr != nil {
if werr := writeAll(w, data); werr != nil {
// {{if .Config.Debug}}
log.Print("Error writing data: ", werr)
// {{end}}
return werr
return fmt.Errorf("[mtls] write data: %w", werr)
}
return nil
}
@@ -0,0 +1,47 @@
package mtls
import (
"bytes"
"crypto/tls"
"testing"
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
)
func TestWriteEnvelope_NilEnvelope(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
if err := WriteEnvelope(&buf, nil); err == nil {
t.Fatalf("expected error for nil envelope")
}
}
func TestWriteEnvelope_NilWriter(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
t.Fatalf("WriteEnvelope panicked: %v", r)
}
}()
if err := WriteEnvelope(nil, &pb.Envelope{}); err == nil {
t.Fatalf("expected error for nil writer")
}
}
func TestWriteEnvelope_NilTLSConnWriter(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
t.Fatalf("WriteEnvelope panicked: %v", r)
}
}()
var conn *tls.Conn
if err := WriteEnvelope(conn, &pb.Envelope{}); err == nil {
t.Fatalf("expected error for nil *tls.Conn writer")
}
}
+17
View File
@@ -0,0 +1,17 @@
package transports
import "reflect"
// isNilInterface returns true if v is nil, or if v is an interface value holding a nil pointer.
func isNilInterface(v any) bool {
if v == nil {
return true
}
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Interface, reflect.Slice:
return rv.IsNil()
default:
return false
}
}
+28 -2
View File
@@ -25,7 +25,9 @@ import (
// {{end}}
// {{if or .Config.IncludeMTLS .Config.IncludeWG}}
"errors"
"strconv"
// {{end}}
// {{if .Config.Debug}}
@@ -45,8 +47,6 @@ import (
// {{end}}
// {{if .Config.IncludeWG}}
"errors"
"github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
"golang.zx2c4.com/wireguard/device"
@@ -257,6 +257,13 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
if err != nil {
return err
}
if conn == nil {
errMsg := ""
// {{if .Config.Debug}}
errMsg = "mtls connection returned nil conn"
// {{end}}
return errors.New(errMsg)
}
if _, err := conn.Write([]byte(mtls.YamuxPreface)); err != nil {
conn.Close()
return err
@@ -266,6 +273,14 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
conn.Close()
return err
}
if muxSession == nil {
conn.Close()
errMsg := ""
// {{if .Config.Debug}}
errMsg = "[mtls] failed to create yamux session (nil)"
// {{end}}
return errors.New(errMsg)
}
connection.IsOpen = true
go func() {
@@ -292,6 +307,10 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
connection.Cleanup()
return
}
if isNilInterface(stream) {
connection.Cleanup()
return
}
defer stream.Close()
if err := mtls.WriteEnvelope(stream, envelope); err != nil {
connection.Cleanup()
@@ -315,6 +334,10 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
connection.Cleanup()
return
}
if isNilInterface(stream) {
connection.Cleanup()
return
}
defer stream.Close()
if err := mtls.WritePing(stream); err != nil {
connection.Cleanup()
@@ -346,6 +369,9 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
if err != nil {
return
}
if isNilInterface(stream) {
return
}
select {
case streamSem <- struct{}{}:
File diff suppressed because it is too large. Load diff
+1
View File
@@ -195,6 +195,7 @@ service SliverRPC {
rpc Migrate(clientpb.MigrateReq) returns (sliverpb.Migrate);
rpc Execute(sliverpb.ExecuteReq) returns (sliverpb.Execute);
rpc ExecuteWindows(sliverpb.ExecuteWindowsReq) returns (sliverpb.Execute);
rpc ExecuteChildren(sliverpb.ExecuteChildrenReq) returns (sliverpb.ExecuteChildren);
rpc Sideload(sliverpb.SideloadReq) returns (sliverpb.Sideload);
rpc SpawnDll(sliverpb.InvokeSpawnDllReq) returns (sliverpb.SpawnDll);
rpc Screenshot(sliverpb.ScreenshotReq) returns (sliverpb.Screenshot);
+36
View File
@@ -169,6 +169,7 @@ type SliverRPCClient interface {
Migrate(ctx context.Context, in *clientpb.MigrateReq, opts ...grpc.CallOption) (*sliverpb.Migrate, error)
Execute(ctx context.Context, in *sliverpb.ExecuteReq, opts ...grpc.CallOption) (*sliverpb.Execute, error)
ExecuteWindows(ctx context.Context, in *sliverpb.ExecuteWindowsReq, opts ...grpc.CallOption) (*sliverpb.Execute, error)
ExecuteChildren(ctx context.Context, in *sliverpb.ExecuteChildrenReq, opts ...grpc.CallOption) (*sliverpb.ExecuteChildren, error)
Sideload(ctx context.Context, in *sliverpb.SideloadReq, opts ...grpc.CallOption) (*sliverpb.Sideload, error)
SpawnDll(ctx context.Context, in *sliverpb.InvokeSpawnDllReq, opts ...grpc.CallOption) (*sliverpb.SpawnDll, error)
Screenshot(ctx context.Context, in *sliverpb.ScreenshotReq, opts ...grpc.CallOption) (*sliverpb.Screenshot, error)
@@ -1458,6 +1459,15 @@ func (c *sliverRPCClient) ExecuteWindows(ctx context.Context, in *sliverpb.Execu
return out, nil
}
func (c *sliverRPCClient) ExecuteChildren(ctx context.Context, in *sliverpb.ExecuteChildrenReq, opts ...grpc.CallOption) (*sliverpb.ExecuteChildren, error) {
out := new(sliverpb.ExecuteChildren)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ExecuteChildren", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) Sideload(ctx context.Context, in *sliverpb.SideloadReq, opts ...grpc.CallOption) (*sliverpb.Sideload, error) {
out := new(sliverpb.Sideload)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Sideload", in, out, opts...)
@@ -2181,6 +2191,7 @@ type SliverRPCServer interface {
Migrate(context.Context, *clientpb.MigrateReq) (*sliverpb.Migrate, error)
Execute(context.Context, *sliverpb.ExecuteReq) (*sliverpb.Execute, error)
ExecuteWindows(context.Context, *sliverpb.ExecuteWindowsReq) (*sliverpb.Execute, error)
ExecuteChildren(context.Context, *sliverpb.ExecuteChildrenReq) (*sliverpb.ExecuteChildren, error)
Sideload(context.Context, *sliverpb.SideloadReq) (*sliverpb.Sideload, error)
SpawnDll(context.Context, *sliverpb.InvokeSpawnDllReq) (*sliverpb.SpawnDll, error)
Screenshot(context.Context, *sliverpb.ScreenshotReq) (*sliverpb.Screenshot, error)
@@ -2634,6 +2645,9 @@ func (UnimplementedSliverRPCServer) Execute(context.Context, *sliverpb.ExecuteRe
func (UnimplementedSliverRPCServer) ExecuteWindows(context.Context, *sliverpb.ExecuteWindowsReq) (*sliverpb.Execute, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExecuteWindows not implemented")
}
func (UnimplementedSliverRPCServer) ExecuteChildren(context.Context, *sliverpb.ExecuteChildrenReq) (*sliverpb.ExecuteChildren, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExecuteChildren not implemented")
}
func (UnimplementedSliverRPCServer) Sideload(context.Context, *sliverpb.SideloadReq) (*sliverpb.Sideload, error) {
return nil, status.Errorf(codes.Unimplemented, "method Sideload not implemented")
}
@@ -5115,6 +5129,24 @@ func _SliverRPC_ExecuteWindows_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_ExecuteChildren_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.ExecuteChildrenReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).ExecuteChildren(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/ExecuteChildren",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).ExecuteChildren(ctx, req.(*sliverpb.ExecuteChildrenReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_Sideload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.SideloadReq)
if err := dec(in); err != nil {
@@ -6645,6 +6677,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "ExecuteWindows",
Handler: _SliverRPC_ExecuteWindows_Handler,
},
{
MethodName: "ExecuteChildren",
Handler: _SliverRPC_ExecuteChildren_Handler,
},
{
MethodName: "Sideload",
Handler: _SliverRPC_Sideload_Handler,
+5
View File
@@ -355,6 +355,9 @@ const (
// MsgShellResizeReq - Resize a shell PTY
MsgShellResizeReq
// MsgExecuteChildrenReq - List tracked background execute child processes
MsgExecuteChildrenReq
)
// Constants to replace enums
@@ -460,6 +463,8 @@ func MsgNumber(request proto.Message) uint32 {
return MsgIfconfig
case *ExecuteReq:
return MsgExecuteReq
case *ExecuteChildrenReq:
return MsgExecuteChildrenReq
case *TerminateReq:
return MsgTerminateReq
case *Terminate:
File diff suppressed because it is too large. Load diff
+27
View File
@@ -517,6 +517,7 @@ message ExecuteReq {
string Stderr = 5;
bool EnvInheritance = 6;
map<string, string> Env = 7;
bool Background = 8;
uint32 PPid = 10;
@@ -531,6 +532,7 @@ message ExecuteWindowsReq {
string Stderr = 5;
bool UseToken = 6;
bool HideWindow = 7;
bool Background = 8;
uint32 PPid = 10;
commonpb.Request Request = 9;
@@ -545,6 +547,31 @@ message Execute {
commonpb.Response Response = 9;
}
message ExecuteChildrenReq {
commonpb.Request Request = 9;
}
message ExecuteChild {
int32 Pid = 1;
string Path = 2;
repeated string Args = 3;
int64 StartTime = 4;
bool Exited = 5;
int32 ExitCode = 6;
int64 ExitTime = 7;
string Stdout = 8;
string Stderr = 11;
string Error = 12;
}
message ExecuteChildren {
repeated ExecuteChild Children = 1;
commonpb.Response Response = 9;
}
message SideloadReq {
bytes Data = 1;
string ProcessName = 2;
+36
View File
@@ -0,0 +1,36 @@
package rpc
/*
Sliver Implant Framework
Copyright (C) 2020 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
// ExecuteChildren - List tracked background execute child processes
func (rpc *Server) ExecuteChildren(ctx context.Context, req *sliverpb.ExecuteChildrenReq) (*sliverpb.ExecuteChildren, error) {
resp := &sliverpb.ExecuteChildren{Response: &commonpb.Response{}}
err := rpc.GenericHandler(req, resp)
if err != nil {
return nil, err
}
return resp, nil
}