Compare commits

...
Author SHA1 Message Date
moloch-- 13bf9d0a01 Implement --rc for scripting initial inputs 2026-01-04 17:51:59 -08:00
moloch-- dc736f6095 Update readme 2026-01-04 12:18:58 -08:00
Joe e02d53ce67 Merge pull request #2088 from BishopFox/fix/readline
Reduce flickering text in readline
2026-01-04 13:02:14 -07:00
Joe 064cd6a2cc Merge pull request #2087 from BishopFox/fix/mods3
Rename implant/sliver imports
2026-01-04 12:00:46 -07:00
moloch-- b7c336cb76 Rename implant/sliver imports 2026-01-04 10:17:56 -08:00
11 changed files with 213 additions and 13 deletions

No files matched your search

+1
View File
@@ -5,6 +5,7 @@
/artifacts
/artifacts/**
*.rc
/Dockerfile.*
/*.sdk.tar.xz
-1
View File
@@ -46,4 +46,3 @@ Please take a moment and fill out [our survey](https://forms.gle/SwVsHFNh24ChG58
### License - GPLv3
Sliver is licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html), some sub-components may have separate licenses. See their respective subdirectories in this project for details.
+1
View File
@@ -51,6 +51,7 @@ func init() {
defer logFile.Close()
rootCmd.TraverseChildren = true
rootCmd.Flags().String(RCFlagName, "", "path to rc script file")
// Create the console client, without any RPC or commands bound to it yet.
// This created before anything so that multiple commands can make use of
+9 -3
View File
@@ -40,6 +40,7 @@ func consoleCmd(con *console.SliverClient) *cobra.Command {
Short: "Start the sliver client console",
}
consoleCmd.Flags().String(RCFlagName, "", "path to rc script file")
consoleCmd.RunE, consoleCmd.PersistentPostRunE = consoleRunnerCmd(con, true)
return consoleCmd
}
@@ -47,7 +48,7 @@ func consoleCmd(con *console.SliverClient) *cobra.Command {
func consoleRunnerCmd(con *console.SliverClient, run bool) (pre, post func(cmd *cobra.Command, args []string) error) {
var ln *grpc.ClientConn
pre = func(_ *cobra.Command, _ []string) error {
pre = func(cmd *cobra.Command, _ []string) error {
configs := assets.GetConfigs()
if len(configs) == 0 {
@@ -59,13 +60,18 @@ func consoleRunnerCmd(con *console.SliverClient, run bool) (pre, post func(cmd *
return nil
}
rcScript, err := ReadRCScript(cmd)
if err != nil {
fmt.Printf("Failed to read rc script: %s\n", err)
return nil
}
// Don't clobber output when simply running an implant command from system shell.
if run {
fmt.Printf("Connecting to %s:%d ...\n", config.LHost, config.LPort)
}
var rpc rpcpb.SliverRPCClient
var err error
rpc, ln, err = transport.MTLSConnect(config)
if err != nil {
@@ -76,7 +82,7 @@ func consoleRunnerCmd(con *console.SliverClient, run bool) (pre, post func(cmd *
// Wait for any connection state changes and exit if the connection is lost.
go handleConnectionLost(ln)
return console.StartClient(con, rpc, command.ServerCommands(con, nil), command.SliverCommands(con), run)
return console.StartClient(con, rpc, command.ServerCommands(con, nil), command.SliverCommands(con), run, rcScript)
}
// Close the RPC connection once exiting
+31
View File
@@ -0,0 +1,31 @@
package cli
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
const RCFlagName = "rc"
func ReadRCScript(cmd *cobra.Command) (string, error) {
if cmd == nil {
return "", nil
}
if cmd.Flags().Lookup(RCFlagName) == nil {
return "", nil
}
rcPath, err := cmd.Flags().GetString(RCFlagName)
if err != nil {
return "", err
}
if rcPath == "" {
return "", nil
}
data, err := os.ReadFile(rcPath)
if err != nil {
return "", fmt.Errorf("read rc script %q: %w", rcPath, err)
}
return string(data), nil
}
+77 -3
View File
@@ -41,6 +41,7 @@ import (
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/util"
"github.com/gofrs/uuid"
"github.com/kballard/go-shellquote"
"github.com/reeflective/console"
"github.com/reeflective/readline"
"github.com/spf13/cobra"
@@ -159,7 +160,7 @@ func NewConsole(isServer bool) *SliverClient {
// Init requires a working RPC connection to the sliver server, and 2 different sets of commands.
// If run is true, the console application is started, making this call blocking. Otherwise, commands and
// RPC connection are bound to the console (making the console ready to run), but the console does not start.
func StartClient(con *SliverClient, rpc rpcpb.SliverRPCClient, serverCmds, sliverCmds console.Commands, run bool) error {
func StartClient(con *SliverClient, rpc rpcpb.SliverRPCClient, serverCmds, sliverCmds console.Commands, run bool, rcScript string) error {
con.Rpc = rpc
con.IsCLI = !run
@@ -206,6 +207,13 @@ func StartClient(con *SliverClient, rpc rpcpb.SliverRPCClient, serverCmds, slive
con.setupAsciicastRecord(asciicastLog, asciicastStream)
}
if rcScript != "" {
originalPrintf := con.printf
con.printf = fmt.Printf
con.runRCScript(serverCmds, sliverCmds, rcScript)
con.printf = originalPrintf
}
if !con.IsCLI {
return con.App.Start()
}
@@ -213,6 +221,71 @@ func StartClient(con *SliverClient, rpc rpcpb.SliverRPCClient, serverCmds, slive
return nil
}
func (con *SliverClient) runRCScript(serverCmds, sliverCmds console.Commands, rcScript string) {
scanner := bufio.NewScanner(strings.NewReader(rcScript))
lineNumber := 0
for scanner.Scan() {
lineNumber++
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
if err := con.runRCLine(serverCmds, sliverCmds, line); err != nil {
con.PrintErrorf("rc line %d error: %s", lineNumber, err)
}
}
if err := scanner.Err(); err != nil {
con.PrintErrorf("rc script error: %s", err)
}
}
func (con *SliverClient) runRCLine(serverCmds, sliverCmds console.Commands, line string) error {
args, err := shellquote.Split(line)
if err != nil {
return fmt.Errorf("parse error: %w", err)
}
for _, hook := range con.App.PreCmdRunLineHooks {
args, err = hook(args)
if err != nil {
return fmt.Errorf("pre-run line error: %w", err)
}
}
if len(args) == 0 {
return nil
}
menu := con.App.ActiveMenu()
if menu.Name() == consts.ImplantMenu {
menu.Command = sliverCmds()
} else {
menu.Command = serverCmds()
}
target, _, _ := menu.Command.Find(args)
if err := menu.CheckIsAvailable(target); err != nil {
return err
}
for _, hook := range con.App.PreCmdRunHooks {
if err := hook(); err != nil {
return fmt.Errorf("pre-run error: %w", err)
}
}
menu.SetArgs(args)
menu.SetContext(context.Background())
if err := menu.Execute(); err != nil {
return err
}
return nil
}
func (con *SliverClient) startEventLoop() {
eventStream, err := con.Rpc.Events(context.Background(), &commonpb.Empty{})
if err != nil {
@@ -341,11 +414,12 @@ func (con *SliverClient) triggerReactions(event *clientpb.Event) {
con.ActiveTarget.Set(currentActiveSession, currentActiveBeacon)
}()
if event.EventType == consts.SessionOpenedEvent {
switch event.EventType {
case consts.SessionOpenedEvent:
con.ActiveTarget.Set(nil, nil)
con.ActiveTarget.Set(event.Session, nil)
} else if event.EventType == consts.BeaconRegisteredEvent {
case consts.BeaconRegisteredEvent:
con.ActiveTarget.Set(nil, nil)
beacon := &clientpb.Beacon{}
+10 -1
View File
@@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
clientcli "github.com/bishopfox/sliver/client/cli"
"github.com/bishopfox/sliver/server/assets"
"github.com/bishopfox/sliver/server/c2"
"github.com/bishopfox/sliver/server/certs"
@@ -72,6 +73,8 @@ func initConsoleLogging(appDir string) *os.File {
}
func init() {
rootCmd.Flags().String(clientcli.RCFlagName, "", "path to rc script file")
// Unpack
unpackCmd.Flags().BoolP(forceFlagStr, "f", false, "Force unpack and overwrite")
rootCmd.AddCommand(unpackCmd)
@@ -147,8 +150,14 @@ var rootCmd = &cobra.Command{
if serverConfig.DaemonMode {
daemon.Start(daemon.BlankHost, daemon.BlankPort, serverConfig.DaemonConfig.Tailscale)
} else {
rcScript, err := clientcli.ReadRCScript(cmd)
if err != nil {
fmt.Printf("Failed to read rc script: %s\n", err)
return
}
os.Args = os.Args[:1] // Hide cli from grumble console
console.Start()
console.Start(rcScript)
}
},
}
+2 -2
View File
@@ -38,7 +38,7 @@ import (
)
// Start - Starts the server console
func Start() {
func Start(rcScript string) {
_, ln, _ := transport.LocalListener()
ctxDialer := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return ln.Dial()
@@ -57,7 +57,7 @@ func Start() {
defer conn.Close()
localRPC := rpcpb.NewSliverRPCClient(conn)
con := console.NewConsole(false)
console.StartClient(con, localRPC, command.ServerCommands(con, serverOnlyCmds), command.SliverCommands(con), true)
console.StartClient(con, localRPC, command.ServerCommands(con, serverOnlyCmds), command.SliverCommands(con), true, rcScript)
con.App.Start()
}
+13 -2
View File
@@ -533,12 +533,23 @@ func renderSliverGoCode(name string, build *clientpb.ImplantBuild, config *clien
goPackage = config.GoPackage
}
}
result, err := goname.RenameModule(sliverPkgDir, goPackage)
modResult, err := goname.RenameModule(sliverPkgDir, goPackage)
if err != nil {
buildLog.Errorf("Failed to rename module: %s", err)
return "", err
}
buildLog.Infof("Renamed module: %s -> %s (go.mod updated: %v)", result.OldModule, result.NewModule, result.GoModUpdated)
buildLog.Infof("Renamed module: %s -> %s (go.mod updated: %v)", modResult.OldModule, modResult.NewModule, modResult.GoModUpdated)
// Rename Import Paths
buildLog.Infof("Renaming import paths ...")
oldImportPrefix := path.Join(modResult.NewModule, "implant", "sliver")
newImportPrefix := path.Join(modResult.NewModule, "runc", "cgroup")
importResult, err := goname.RenameImport(sliverPkgDir, oldImportPrefix, newImportPrefix)
if err != nil {
buildLog.Errorf("Failed to rename imports: %s", err)
return "", err
}
buildLog.Infof("Renamed imports (%d files updated)", importResult.FilesUpdated)
}
return sliverPkgDir, nil
+64
View File
@@ -2,7 +2,10 @@ package goname
import (
"errors"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
)
@@ -37,6 +40,9 @@ func RenameImport(dir, oldImportPrefix, newImportPrefix string) (*ImportResult,
if result.ImportsUpdated == 0 {
return result, errors.New("no imports updated (check old/new import prefixes)")
}
if err := renameImportDir(dir, oldImportPrefix, newImportPrefix); err != nil {
return result, err
}
return result, nil
}
@@ -68,3 +74,61 @@ func rewriteImportPrefixes(dir, oldImportPrefix, newImportPrefix string, result
return nil
})
}
func renameImportDir(dir, oldImportPrefix, newImportPrefix string) error {
oldParts := splitImportPrefix(oldImportPrefix)
newParts := splitImportPrefix(newImportPrefix)
if len(oldParts) == 0 || len(newParts) == 0 {
return nil
}
for i := 0; i < len(oldParts); i++ {
suffixParts := oldParts[i:]
oldDir := filepath.Join(append([]string{dir}, suffixParts...)...)
info, err := os.Stat(oldDir)
if err != nil {
if os.IsNotExist(err) {
continue
}
return err
}
if !info.IsDir() {
continue
}
if len(newParts) < len(suffixParts) {
return fmt.Errorf("new import prefix has fewer path segments than old import prefix")
}
newSuffixParts := newParts[len(newParts)-len(suffixParts):]
newDir := filepath.Join(append([]string{dir}, newSuffixParts...)...)
if oldDir == newDir {
return nil
}
if _, err := os.Stat(newDir); err == nil {
return fmt.Errorf("rename import dir: target exists: %s", newDir)
} else if !os.IsNotExist(err) {
return err
}
if err := os.MkdirAll(filepath.Dir(newDir), 0700); err != nil {
return err
}
return os.Rename(oldDir, newDir)
}
return nil
}
func splitImportPrefix(prefix string) []string {
cleaned := path.Clean(strings.TrimSpace(prefix))
if cleaned == "." || cleaned == "/" {
return nil
}
cleaned = strings.TrimPrefix(cleaned, "/")
if cleaned == "" {
return nil
}
return strings.Split(cleaned, "/")
}
+5 -1
View File
@@ -42,11 +42,15 @@ func TestRenameImportBasic(t *testing.T) {
t.Fatalf("main.go still references old prefix")
}
barImports := importPaths(t, filepath.Join(tmp, "foo", "bar", "bar.go"))
barImports := importPaths(t, filepath.Join(tmp, "acme", "corp", "bar.go"))
if !barImports["acme/corp/baz"] {
t.Fatalf("bar.go import not updated")
}
if _, err := os.Stat(filepath.Join(tmp, "foo", "bar")); !os.IsNotExist(err) {
t.Fatalf("expected foo/bar to be renamed")
}
vendorImports := importPaths(t, filepath.Join(tmp, "vendor", "foo", "bar", "vendor.go"))
if !vendorImports["foo/bar/baz"] {
t.Fatalf("vendor import should remain unchanged")