Files
2022-01-24 10:25:33 -06:00

201 lines
5.5 KiB
Go

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"
"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.PrintErrorf("%s\n", err)
return
}
if session != nil {
con.ActiveTarget.Set(session, nil)
con.PrintInfof("Active session %s (%s)\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
}
if err == nil {
for _, session := range sessions.Sessions {
if strings.HasPrefix(session.ID, id) {
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[string]*clientpb.Session{}
for _, session := range sessions.GetSessions() {
sessionsMap[session.ID] = session
}
var sessionKeys []string
for _, session := range sessions.Sessions {
sessionKeys = append(sessionKeys, session.ID)
}
sort.Strings(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[key]
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
"SESSION",
strings.Split(session.ID, "-")[0],
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\t%s\n",
"BEACON",
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[sessionKeys[index]], nil, nil
}
return nil, beaconsMap[beaconKeys[index-len(sessionKeys)]], nil
}
}
return nil, nil, nil
}
// BeaconAndSessionIDCompleter - BeaconAndSessionIDCompleter for beacon / session ids
func BeaconAndSessionIDCompleter(prefix string, args []string, con *console.SliverConsoleClient) (results []string) {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
return
}
for _, s := range sessions.Sessions {
sid := s.ID
if strings.HasPrefix(sid, prefix) {
results = append(results, s.ID)
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return
}
for _, b := range beacons.Beacons {
if strings.HasPrefix(b.ID, prefix) {
results = append(results, b.ID)
}
}
return
}