mirror of
https://github.com/MrAle98/sliver
synced 2026-06-08 11:54:46 +00:00
3596 lines
123 KiB
Go
3596 lines
123 KiB
Go
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 <https://www.gnu.org/licenses/>.
|
||
|
||
---------------------------------------------------------------------
|
||
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 parameter,
|
||
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 (
|
||
"os"
|
||
|
||
"github.com/bishopfox/sliver/client/assets"
|
||
"github.com/bishopfox/sliver/client/command/alias"
|
||
"github.com/bishopfox/sliver/client/command/armory"
|
||
"github.com/bishopfox/sliver/client/command/backdoor"
|
||
"github.com/bishopfox/sliver/client/command/beacons"
|
||
"github.com/bishopfox/sliver/client/command/builders"
|
||
"github.com/bishopfox/sliver/client/command/completers"
|
||
"github.com/bishopfox/sliver/client/command/cursed"
|
||
"github.com/bishopfox/sliver/client/command/dllhijack"
|
||
"github.com/bishopfox/sliver/client/command/environment"
|
||
"github.com/bishopfox/sliver/client/command/exec"
|
||
"github.com/bishopfox/sliver/client/command/extensions"
|
||
"github.com/bishopfox/sliver/client/command/filesystem"
|
||
"github.com/bishopfox/sliver/client/command/generate"
|
||
"github.com/bishopfox/sliver/client/command/help"
|
||
"github.com/bishopfox/sliver/client/command/hosts"
|
||
"github.com/bishopfox/sliver/client/command/info"
|
||
"github.com/bishopfox/sliver/client/command/jobs"
|
||
"github.com/bishopfox/sliver/client/command/kill"
|
||
"github.com/bishopfox/sliver/client/command/loot"
|
||
"github.com/bishopfox/sliver/client/command/monitor"
|
||
"github.com/bishopfox/sliver/client/command/network"
|
||
"github.com/bishopfox/sliver/client/command/operators"
|
||
"github.com/bishopfox/sliver/client/command/pivots"
|
||
"github.com/bishopfox/sliver/client/command/portfwd"
|
||
operator "github.com/bishopfox/sliver/client/command/prelude-operator"
|
||
"github.com/bishopfox/sliver/client/command/privilege"
|
||
"github.com/bishopfox/sliver/client/command/processes"
|
||
"github.com/bishopfox/sliver/client/command/reaction"
|
||
"github.com/bishopfox/sliver/client/command/reconfig"
|
||
"github.com/bishopfox/sliver/client/command/registry"
|
||
"github.com/bishopfox/sliver/client/command/rportfwd"
|
||
"github.com/bishopfox/sliver/client/command/screenshot"
|
||
"github.com/bishopfox/sliver/client/command/sessions"
|
||
"github.com/bishopfox/sliver/client/command/settings"
|
||
"github.com/bishopfox/sliver/client/command/shell"
|
||
sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai"
|
||
"github.com/bishopfox/sliver/client/command/socks"
|
||
"github.com/bishopfox/sliver/client/command/tasks"
|
||
"github.com/bishopfox/sliver/client/command/update"
|
||
"github.com/bishopfox/sliver/client/command/use"
|
||
"github.com/bishopfox/sliver/client/command/websites"
|
||
"github.com/bishopfox/sliver/client/command/wireguard"
|
||
"github.com/bishopfox/sliver/client/console"
|
||
consts "github.com/bishopfox/sliver/client/constants"
|
||
"github.com/bishopfox/sliver/client/licenses"
|
||
"github.com/desertbit/grumble"
|
||
)
|
||
|
||
const (
|
||
defaultTimeout = 60
|
||
)
|
||
|
||
// BindCommands - Bind commands to a App
|
||
func BindCommands(con *console.SliverConsoleClient) {
|
||
|
||
// Load Reactions
|
||
n, err := reaction.LoadReactions()
|
||
if err != nil && !os.IsNotExist(err) {
|
||
con.PrintErrorf("Failed to load reactions: %s\n", err)
|
||
} else if n > 0 {
|
||
con.PrintInfof("Loaded %d reaction(s) from disk\n", n)
|
||
}
|
||
|
||
// Load Aliases
|
||
aliasManifests := assets.GetInstalledAliasManifests()
|
||
n = 0
|
||
for _, manifest := range aliasManifests {
|
||
_, err = alias.LoadAlias(manifest, con)
|
||
if err != nil {
|
||
con.PrintErrorf("Failed to load alias: %s\n", err)
|
||
continue
|
||
}
|
||
n++
|
||
}
|
||
if 0 < n {
|
||
if n == 1 {
|
||
con.PrintInfof("Loaded %d alias from disk\n", n)
|
||
} else {
|
||
con.PrintInfof("Loaded %d aliases from disk\n", n)
|
||
}
|
||
}
|
||
|
||
// Load Extensions
|
||
extensionManifests := assets.GetInstalledExtensionManifests()
|
||
n = 0
|
||
for _, manifest := range extensionManifests {
|
||
ext, err := extensions.LoadExtensionManifest(manifest)
|
||
// Absorb error in case there's no extensions manifest
|
||
if err != nil {
|
||
con.PrintErrorf("Failed to load extension: %s\n", err)
|
||
continue
|
||
}
|
||
extensions.ExtensionRegisterCommand(ext, con)
|
||
n++
|
||
}
|
||
if 0 < n {
|
||
con.PrintInfof("Loaded %d extension(s) from disk\n", n)
|
||
}
|
||
con.App.SetPrintHelp(help.HelpCmd(con)) // Responsible for display long-form help templates, etc.
|
||
|
||
// [ Aliases ] ---------------------------------------------
|
||
|
||
aliasCmd := &grumble.Command{
|
||
Name: consts.AliasesStr,
|
||
Help: "List current aliases",
|
||
LongHelp: help.GetHelpFor([]string{consts.AliasesStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
alias.AliasesCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
con.App.AddCommand(aliasCmd)
|
||
|
||
aliasCmd.AddCommand(&grumble.Command{
|
||
Name: consts.LoadStr,
|
||
Help: "Load a command alias",
|
||
LongHelp: help.GetHelpFor([]string{consts.AliasesStr, consts.LoadStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
alias.AliasesLoadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("dir-path", "path to the alias directory")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return completers.LocalPathCompleter(prefix, args, con)
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
aliasCmd.AddCommand(&grumble.Command{
|
||
Name: consts.InstallStr,
|
||
Help: "Install a command alias",
|
||
LongHelp: help.GetHelpFor([]string{consts.AliasesStr, consts.InstallStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
alias.AliasesInstallCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("path", "path to the alias directory or tar.gz file")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return completers.LocalPathCompleter(prefix, args, con)
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
aliasCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Remove an alias",
|
||
LongHelp: help.GetHelpFor([]string{consts.RmStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
alias.AliasesRemoveCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "name of the alias to remove")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return alias.AliasCommandNameCompleter(prefix, args, con)
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Armory ] ---------------------------------------------
|
||
|
||
armoryCmd := &grumble.Command{
|
||
Name: consts.ArmoryStr,
|
||
Help: "Automatically download and install extensions/aliases",
|
||
LongHelp: help.GetHelpFor([]string{consts.ArmoryStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("I", "insecure", false, "skip tls certificate validation")
|
||
f.String("p", "proxy", "", "specify a proxy url (e.g. http://localhost:8080)")
|
||
f.Bool("c", "ignore-cache", false, "ignore metadata cache, force refresh")
|
||
f.String("t", "timeout", "15m", "download timeout")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
armory.ArmoryCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
con.App.AddCommand(armoryCmd)
|
||
|
||
armoryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.InstallStr,
|
||
Help: "Install an alias or extension",
|
||
LongHelp: help.GetHelpFor([]string{consts.ArmoryStr, consts.InstallStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("I", "insecure", false, "skip tls certificate validation")
|
||
f.String("p", "proxy", "", "specify a proxy url (e.g. http://localhost:8080)")
|
||
f.Bool("c", "ignore-cache", false, "ignore metadata cache, force refresh")
|
||
f.String("t", "timeout", "15m", "download timeout")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
armory.ArmoryInstallCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "name of the extension or alias to install")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return armory.AliasExtensionOrBundleCompleter(prefix, args, con)
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
armoryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.UpdateStr,
|
||
Help: "Update installed an aliases and extensions",
|
||
LongHelp: help.GetHelpFor([]string{consts.ArmoryStr, consts.UpdateStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("I", "insecure", false, "skip tls certificate validation")
|
||
f.String("p", "proxy", "", "specify a proxy url (e.g. http://localhost:8080)")
|
||
f.Bool("c", "ignore-cache", false, "ignore metadata cache, force refresh")
|
||
f.String("t", "timeout", "15m", "download timeout")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
armory.ArmoryUpdateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
armoryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SearchStr,
|
||
Help: "Search for aliases and extensions by name (regex)",
|
||
LongHelp: help.GetHelpFor([]string{consts.ArmoryStr, consts.SearchStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "a name regular expression")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
armory.ArmorySearchCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Update ] --------------------------------------------------------------
|
||
|
||
con.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 {
|
||
con.Println()
|
||
update.UpdateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
update.VerboseVersionsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Jobs ] -----------------------------------------------------------------
|
||
|
||
con.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 {
|
||
con.Println()
|
||
jobs.JobsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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("L", "lhost", "", "interface to bind server to")
|
||
f.Int("l", "lport", generate.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 {
|
||
con.Println()
|
||
jobs.MTLSListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.WGStr,
|
||
Help: "Start a WireGuard listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.WGStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("L", "lhost", "", "interface to bind server to")
|
||
f.Int("l", "lport", generate.DefaultWGLPort, "udp listen port")
|
||
f.Int("n", "nport", generate.DefaultWGNPort, "virtual tun interface listen port")
|
||
f.Int("x", "key-port", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port")
|
||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
jobs.WGListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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.String("L", "lhost", "", "interface to bind server to")
|
||
f.Int("l", "lport", generate.DefaultDNSLPort, "udp listen port")
|
||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
jobs.DNSListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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.String("L", "lhost", "", "interface to bind server to")
|
||
f.Int("l", "lport", generate.DefaultHTTPLPort, "tcp listen port")
|
||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||
f.String("T", "long-poll-timeout", "1s", "server-side long poll timeout")
|
||
f.String("J", "long-poll-jitter", "2s", "server-side long poll jitter")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
jobs.HTTPListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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.String("L", "lhost", "", "interface to bind server to")
|
||
f.Int("l", "lport", generate.DefaultHTTPSLPort, "tcp listen port")
|
||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||
f.String("T", "long-poll-timeout", "1s", "server-side long poll timeout")
|
||
f.String("J", "long-poll-jitter", "2s", "server-side long poll jitter")
|
||
|
||
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.Bool("E", "disable-randomized-jarm", false, "disable randomized jarm fingerprints")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
jobs.HTTPSListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.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 name 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)")
|
||
f.StringL("aes-encrypt-key", "", "encrypt stage with AES encryption key")
|
||
f.StringL("aes-encrypt-iv", "", "encrypt stage with AES encryption iv")
|
||
f.String("C", "compress", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)")
|
||
f.Bool("P", "prepend-size", false, "prepend the size of the stage to the payload (to use with MSF stagers)")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
jobs.StageListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Operators ] --------------------------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.OperatorsStr,
|
||
Help: "Manage operators",
|
||
LongHelp: help.GetHelpFor([]string{consts.OperatorsStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
operators.OperatorsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.MultiplayerHelpGroup,
|
||
})
|
||
|
||
// [ Reconfig ] ---------------------------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.ReconfigStr,
|
||
Help: "Reconfigure the active beacon/session",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReconfigStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("r", "reconnect-interval", "", "reconnect interval for implant")
|
||
f.String("i", "beacon-interval", "", "beacon callback interval")
|
||
f.String("j", "beacon-jitter", "", "beacon callback jitter (random up to)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reconfig.ReconfigCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.RenameStr,
|
||
Help: "Rename the active beacon/session",
|
||
LongHelp: help.GetHelpFor([]string{consts.RenameStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("n", "name", "", "change implant name to")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reconfig.RenameCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Sessions ] --------------------------------------------------------------
|
||
|
||
sessionsCmd := &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 session")
|
||
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.Bool("F", "force", false, "force session action without waiting for results")
|
||
|
||
f.String("f", "filter", "", "filter sessions by substring")
|
||
f.String("e", "filter-re", "", "filter sessions by regular expression")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
sessions.SessionsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
sessionsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.PruneStr,
|
||
Help: "Kill all stale/dead sessions",
|
||
LongHelp: help.GetHelpFor([]string{consts.SessionsStr, consts.PruneStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("F", "force", false, "Force the killing of stale/dead sessions")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
sessions.SessionsPruneCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
con.App.AddCommand(sessionsCmd)
|
||
|
||
con.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 {
|
||
con.Println()
|
||
sessions.BackgroundCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.KillStr,
|
||
Help: "Kill a session",
|
||
LongHelp: help.GetHelpFor([]string{consts.KillStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
kill.KillCmd(ctx, con)
|
||
con.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,
|
||
})
|
||
|
||
openSessionCmd := &grumble.Command{
|
||
Name: consts.InteractiveStr,
|
||
Help: "Task a beacon to open an interactive session (Beacon only)",
|
||
LongHelp: help.GetHelpFor([]string{consts.InteractiveStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("m", "mtls", "", "mtls connection strings")
|
||
f.String("g", "wg", "", "wg connection strings")
|
||
f.String("b", "http", "", "http(s) connection strings")
|
||
f.String("n", "dns", "", "dns connection strings")
|
||
f.String("p", "named-pipe", "", "namedpipe connection strings")
|
||
f.String("i", "tcp-pivot", "", "tcppivot connection strings")
|
||
|
||
f.String("d", "delay", "0s", "delay opening the session (after checkin) for a given period of time")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
sessions.InteractiveCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
}
|
||
con.App.AddCommand(openSessionCmd)
|
||
|
||
// [ Close ] --------------------------------------------------------------
|
||
closeSessionCmd := &grumble.Command{
|
||
Name: consts.CloseStr,
|
||
Help: "Close an interactive session without killing the remote process",
|
||
LongHelp: help.GetHelpFor([]string{consts.CloseStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
sessions.CloseSessionCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
}
|
||
con.App.AddCommand(closeSessionCmd)
|
||
|
||
// [ Tasks ] --------------------------------------------------------------
|
||
|
||
tasksCmd := &grumble.Command{
|
||
Name: consts.TasksStr,
|
||
Help: "Beacon task management",
|
||
LongHelp: help.GetHelpFor([]string{consts.TasksStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
tasks.TasksCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
tasksCmd.AddCommand(&grumble.Command{
|
||
Name: consts.FetchStr,
|
||
Help: "Fetch the details of a beacon task",
|
||
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("id", "beacon task ID", grumble.Default(""))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
tasks.TasksFetchCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
tasksCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CancelStr,
|
||
Help: "Cancel a pending beacon task",
|
||
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("id", "beacon task ID", grumble.Default(""))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
tasks.TasksCancelCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(tasksCmd)
|
||
|
||
// [ Use ] --------------------------------------------------------------
|
||
|
||
useCmd := &grumble.Command{
|
||
Name: consts.UseStr,
|
||
Help: "Switch the active session or beacon",
|
||
LongHelp: help.GetHelpFor([]string{consts.UseStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("id", "beacon or session ID", grumble.Default(""))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
use.UseCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return use.BeaconAndSessionIDCompleter(prefix, args, con)
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
useCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SessionsStr,
|
||
Help: "Switch the active session",
|
||
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
use.UseSessionCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
useCmd.AddCommand(&grumble.Command{
|
||
Name: consts.BeaconsStr,
|
||
Help: "Switch the active beacon",
|
||
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
use.UseBeaconCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(useCmd)
|
||
|
||
// [ Settings ] --------------------------------------------------------------
|
||
|
||
settingsCmd := &grumble.Command{
|
||
Name: consts.SettingsStr,
|
||
Help: "Manage client settings",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SaveStr,
|
||
Help: "Save the current settings to disk",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.SaveStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsSaveCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.TablesStr,
|
||
Help: "Modify tables setting (style)",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.TablesStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsTablesCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: "beacon-autoresults",
|
||
Help: "Automatically display beacon task results when completed",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "beacon-autoresults"}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsBeaconsAutoResultCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: "autoadult",
|
||
Help: "Automatically accept OPSEC warnings",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "autoadult"}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsAutoAdultCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: "always-overflow",
|
||
Help: "Disable table pagination",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "always-overflow"}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsAlwaysOverflow(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
settingsCmd.AddCommand(&grumble.Command{
|
||
Name: "small-terminal",
|
||
Help: "Set the small terminal width",
|
||
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "small-terminal"}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
settings.SettingsSmallTerm(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(settingsCmd)
|
||
|
||
// [ Info ] --------------------------------------------------------------
|
||
|
||
con.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(""))
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return use.BeaconAndSessionIDCompleter(prefix, args, con)
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
info.InfoCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
info.PingCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
info.PIDCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
info.UIDCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
info.GIDCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
info.WhoamiCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Shell ] --------------------------------------------------------------
|
||
|
||
con.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 {
|
||
con.Println()
|
||
shell.ShellCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Shellcode Encoders ] --------------------------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.ShikataGaNai,
|
||
Help: "Polymorphic binary shellcode encoder (ノ ゜Д゜)ノ ︵ 仕方がない",
|
||
LongHelp: help.GetHelpFor([]string{consts.ShikataGaNai}),
|
||
Args: func(a *grumble.Args) {
|
||
a.String("shellcode", "binary shellcode file path")
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("s", "save", "", "save output to local file")
|
||
|
||
f.String("a", "arch", "amd64", "architecture of shellcode")
|
||
f.Int("i", "iterations", 1, "number of iterations")
|
||
f.String("b", "bad-chars", "", "hex encoded bad characters to avoid (e.g. 0001)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
sgn.ShikataGaNaiCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Exec ] --------------------------------------------------------------
|
||
|
||
con.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("o", "output", false, "capture command output")
|
||
f.Bool("s", "save", false, "save output to a file")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.Bool("S", "ignore-stderr", false, "don't print STDERR output")
|
||
f.String("O", "stdout", "", "remote path to redirect STDOUT to")
|
||
f.String("E", "stderr", "", "remote path to redirect STDERR to")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
f.Uint("P", "ppid", 0, "parent process id (optional, Windows only)")
|
||
|
||
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 {
|
||
con.Println()
|
||
exec.ExecuteCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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("i", "in-process", false, "Run in the current sliver process")
|
||
f.String("r", "runtime", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
|
||
f.Bool("s", "save", false, "save output to file")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
f.Uint("P", "ppid", 0, "parent process id (optional)")
|
||
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
|
||
f.Bool("M", "amsi-bypass", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
|
||
f.Bool("E", "etw-bypass", false, "Bypass ETW on Windows (only supported when used with --in-process)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
exec.ExecuteAssemblyCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
exec.ExecuteShellcodeCmd(ctx, con)
|
||
con.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.Bool("S", "shikata-ga-nai", false, "encode shellcode using shikata ga nai prior to execution")
|
||
f.String("A", "architecture", "amd64", "architecture of the shellcode: 386, amd64 (used with --shikata-ga-nai flag)")
|
||
f.Int("I", "iterations", 1, "number of encoding iterations (used with --shikata-ga-nai flag)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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("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("w", "unicode", false, "Command line is passed to unmanaged DLL function in UNICODE format. (default is ANSI)")
|
||
f.Bool("s", "save", false, "save output to file")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes")
|
||
f.Uint("P", "ppid", 0, "parent process id (optional)")
|
||
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("filepath", "path the shared library file")
|
||
a.StringList("args", "arguments for the binary", grumble.Default([]string{}))
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
exec.SideloadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
|
||
con.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.Bool("X", "loot", false, "save output as loot")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes")
|
||
f.Uint("P", "ppid", 0, "parent process id (optional)")
|
||
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
|
||
},
|
||
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 {
|
||
con.Println()
|
||
exec.SpawnDllCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
exec.MigrateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.Uint("pid", "pid")
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("S", "disable-sgn", true, "disable shikata ga nai shellcode encoder")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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("L", "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 {
|
||
con.Println()
|
||
exec.MsfCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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("L", "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 {
|
||
con.Println()
|
||
exec.MsfInjectCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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")
|
||
f.String("c", "custom-exe", "", "custom service executable to use instead of generating a new Sliver")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
exec.PsExecCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("hostname", "hostname")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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")
|
||
f.String("c", "kerberos-config", "/etc/krb5.conf", "path to remote Kerberos config file")
|
||
f.String("k", "kerberos-keytab", "", "path to Kerberos keytab file")
|
||
f.String("r", "kerberos-realm", "", "Kerberos realm")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
exec.SSHCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Generate ] --------------------------------------------------------------
|
||
|
||
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 (e.g. overwrite user space hooks)")
|
||
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
|
||
f.String("I", "template", "sliver", "implant code template")
|
||
f.Bool("E", "external-builder", false, "use an external builder")
|
||
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
|
||
|
||
f.String("c", "canary", "", "canary domain(s)")
|
||
|
||
f.String("m", "mtls", "", "mtls connection strings")
|
||
f.String("g", "wg", "", "wg connection strings")
|
||
f.String("b", "http", "", "http(s) connection strings")
|
||
f.String("n", "dns", "", "dns connection strings")
|
||
f.String("p", "named-pipe", "", "named-pipe connection strings")
|
||
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
|
||
|
||
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
|
||
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
|
||
|
||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||
|
||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
|
||
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
|
||
|
||
f.String("w", "limit-datetime", "", "limit execution to before datetime")
|
||
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
|
||
f.String("y", "limit-username", "", "limit execution to specified username")
|
||
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
|
||
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
|
||
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
|
||
|
||
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
|
||
f.String("s", "save", "", "directory/file to the binary to")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.GenerateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
generateCmd.AddCommand(&grumble.Command{
|
||
Name: consts.BeaconStr,
|
||
Help: "Generate a beacon binary",
|
||
LongHelp: help.GetHelpFor([]string{consts.GenerateStr, consts.BeaconStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int64("D", "days", 0, "beacon interval days")
|
||
f.Int64("H", "hours", 0, "beacon interval hours")
|
||
f.Int64("M", "minutes", 0, "beacon interval minutes")
|
||
f.Int64("S", "seconds", 60, "beacon interval seconds")
|
||
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
|
||
|
||
// Generate flags
|
||
f.String("o", "os", "windows", "operating system")
|
||
f.String("a", "arch", "amd64", "cpu architecture")
|
||
f.String("N", "name", "", "agent name")
|
||
f.Bool("d", "debug", false, "enable debug features")
|
||
f.Bool("e", "evasion", false, "enable evasion features (e.g. overwrite user space hooks)")
|
||
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
|
||
f.String("I", "template", "sliver", "implant code template")
|
||
f.Bool("E", "external-builder", false, "use an external builder")
|
||
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
|
||
|
||
f.String("c", "canary", "", "canary domain(s)")
|
||
|
||
f.String("m", "mtls", "", "mtls connection strings")
|
||
f.String("g", "wg", "", "wg connection strings")
|
||
f.String("b", "http", "", "http(s) connection strings")
|
||
f.String("n", "dns", "", "dns connection strings")
|
||
f.String("p", "named-pipe", "", "named-pipe connection strings")
|
||
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
|
||
|
||
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
|
||
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
|
||
|
||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||
|
||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
|
||
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
|
||
|
||
f.String("w", "limit-datetime", "", "limit execution to before datetime")
|
||
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
|
||
f.String("y", "limit-username", "", "limit execution to specified username")
|
||
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
|
||
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
|
||
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
|
||
|
||
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
|
||
f.String("s", "save", "", "directory/file to the binary to")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.GenerateBeaconCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
generateCmd.AddCommand(&grumble.Command{
|
||
Name: consts.StagerStr,
|
||
Help: "Generate a stager using Metasploit (requires local Metasploit installation)",
|
||
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("l", "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 {
|
||
con.Println()
|
||
generate.GenerateStagerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
generateCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CompilerInfoStr,
|
||
Help: "Get information about the server's compiler",
|
||
LongHelp: help.GetHelpFor([]string{consts.CompilerInfoStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.GenerateInfoCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(generateCmd)
|
||
|
||
con.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 {
|
||
con.Println()
|
||
generate.RegenerateCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
generate.ProfilesCmd(ctx, con)
|
||
con.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("s", "save", "", "directory/file to the binary to")
|
||
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "name of the profile", grumble.Default(""))
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return generate.ProfileNameCompleter(prefix, args, con)
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ProfilesGenerateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
profilesNewCmd := &grumble.Command{
|
||
Name: consts.NewStr,
|
||
Help: "Create a new implant profile (interactive session)",
|
||
LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
|
||
// Generate 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("l", "skip-symbols", false, "skip symbol obfuscation")
|
||
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
|
||
|
||
f.String("c", "canary", "", "canary domain(s)")
|
||
|
||
f.String("N", "name", "", "implant name")
|
||
f.String("m", "mtls", "", "mtls connection strings")
|
||
f.String("g", "wg", "", "wg connection strings")
|
||
f.String("b", "http", "", "http(s) connection strings")
|
||
f.String("n", "dns", "", "dns connection strings")
|
||
f.String("p", "named-pipe", "", "named-pipe connection strings")
|
||
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
|
||
|
||
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
|
||
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
|
||
|
||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||
|
||
f.String("I", "template", "sliver", "implant code template")
|
||
|
||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
|
||
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
|
||
|
||
f.String("w", "limit-datetime", "", "limit execution to before datetime")
|
||
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
|
||
f.String("y", "limit-username", "", "limit execution to specified username")
|
||
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
|
||
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
|
||
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
|
||
|
||
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.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "name of the profile", grumble.Default(""))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ProfilesNewCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
profilesCmd.AddCommand(profilesNewCmd)
|
||
|
||
// New Beacon Profile Command
|
||
profilesNewCmd.AddCommand(&grumble.Command{
|
||
Name: consts.BeaconStr,
|
||
Help: "Create a new implant profile (beacon)",
|
||
LongHelp: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr, consts.BeaconStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int64("D", "days", 0, "beacon interval days")
|
||
f.Int64("H", "hours", 0, "beacon interval hours")
|
||
f.Int64("M", "minutes", 0, "beacon interval minutes")
|
||
f.Int64("S", "seconds", 60, "beacon interval seconds")
|
||
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
|
||
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
|
||
|
||
// Generate 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("l", "skip-symbols", false, "skip symbol obfuscation")
|
||
|
||
f.String("c", "canary", "", "canary domain(s)")
|
||
|
||
f.String("N", "name", "", "implant name")
|
||
f.String("m", "mtls", "", "mtls connection strings")
|
||
f.String("g", "wg", "", "wg connection strings")
|
||
f.String("b", "http", "", "http(s) connection strings")
|
||
f.String("n", "dns", "", "dns connection strings")
|
||
f.String("p", "named-pipe", "", "named-pipe connection strings")
|
||
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
|
||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||
|
||
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
|
||
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
|
||
|
||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||
|
||
f.String("I", "template", "sliver", "implant code template")
|
||
|
||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
|
||
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
|
||
|
||
f.String("w", "limit-datetime", "", "limit execution to before datetime")
|
||
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
|
||
f.String("y", "limit-username", "", "limit execution to specified username")
|
||
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
|
||
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
|
||
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
|
||
|
||
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.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "name of the profile", grumble.Default(""))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ProfilesNewBeaconCmd(ctx, con)
|
||
con.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("name", "name of the profile", grumble.Default(""))
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return generate.ProfileNameCompleter(prefix, args, con)
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ProfilesRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.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.String("o", "os", "", "filter builds by operating system")
|
||
f.String("a", "arch", "", "filter builds by cpu architecture")
|
||
f.String("f", "format", "", "filter builds by artifact format")
|
||
f.Bool("s", "only-sessions", false, "filter interactive sessions")
|
||
f.Bool("b", "only-beacons", false, "filter beacons")
|
||
f.Bool("d", "no-debug", false, "filter builds by debug flag")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ImplantsCmd(ctx, con)
|
||
con.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("name", "implant name", grumble.Default(""))
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return generate.ImplantBuildNameCompleter(prefix, args, generate.ImplantBuildFilter{}, con)
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
generate.ImplantsRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(implantBuildsCmd)
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.CanariesStr,
|
||
Help: "List previously generated canaries",
|
||
LongHelp: help.GetHelpFor([]string{consts.CanariesStr}),
|
||
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 {
|
||
con.Println()
|
||
generate.CanariesCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Filesystem ] ---------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.MvStr,
|
||
Help: "Move or rename a file",
|
||
LongHelp: help.GetHelpFor([]string{consts.MvStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("src", "path to source file")
|
||
a.String("dst", "path to dest file")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
err := filesystem.MvCmd(ctx, con)
|
||
return err
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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")
|
||
f.Bool("r", "reverse", false, "reverse sort order")
|
||
f.Bool("m", "modified", false, "sort by modified time")
|
||
f.Bool("s", "size", false, "sort by size")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("path", "path to enumerate", grumble.Default("."))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
filesystem.LsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
filesystem.RmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
filesystem.MkdirCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
filesystem.CdCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
filesystem.PwdCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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", "hex", false, "display as a hex dump")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
f.String("T", "type", "", "force a specific loot type (file/cred) if looting (optional)")
|
||
f.String("F", "file-type", "", "force a specific file type (binary/text) if looting (optional)")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("path", "path to the file to print")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
filesystem.CatCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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")
|
||
f.String("T", "type", "", "force a specific loot type (file/cred) if looting")
|
||
f.String("F", "file-type", "", "force a specific file type (binary/text) if looting")
|
||
f.String("n", "name", "", "name to assign the download if looting")
|
||
f.Bool("r", "recurse", false, "recursively download all files in a directory")
|
||
},
|
||
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 {
|
||
con.Println()
|
||
filesystem.DownloadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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")
|
||
|
||
f.Bool("i", "ioc", false, "track uploaded file as an ioc")
|
||
},
|
||
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 {
|
||
con.Println()
|
||
filesystem.UploadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Network ] ---------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.IfconfigStr,
|
||
Help: "View network interface configurations",
|
||
LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("A", "all", false, "show all network adapters (default only shows IPv4)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
network.IfconfigCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.NetstatStr,
|
||
Help: "Print network connection information",
|
||
LongHelp: help.GetHelpFor([]string{consts.NetstatStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
network.NetstatCmd(ctx, con)
|
||
con.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.Bool("n", "numeric", false, "display numeric addresses (disable hostname resolution)")
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Processes ] ---------------------------------------------
|
||
|
||
con.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.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||
f.Bool("T", "tree", false, "print process tree")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
processes.PsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.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.String("s", "save", "", "save to file (will overwrite if exists)")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.String("N", "loot-name", "", "name to assign when adding the memory dump to the loot store (optional)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
processes.ProcdumpCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.TerminateStr,
|
||
Help: "Terminate a process on the remote system",
|
||
LongHelp: help.GetHelpFor([]string{consts.TerminateStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
processes.TerminateCmd(ctx, con)
|
||
con.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,
|
||
})
|
||
|
||
// [ Privileges ] ---------------------------------------------
|
||
|
||
con.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", "", "user to impersonate")
|
||
f.String("p", "process", "", "process to start")
|
||
f.String("a", "args", "", "arguments for the process")
|
||
f.String("d", "domain", "", "domain of the user")
|
||
f.String("P", "password", "", "password of the user")
|
||
f.Bool("s", "show-window", false, `
|
||
Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.`)
|
||
f.Bool("n", "net-only", false, "use ")
|
||
f.Int("t", "timeout", 30, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
privilege.RunAsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
privilege.ImpersonateCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", 30, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
privilege.RevToSelfCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", 30, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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 {
|
||
con.Println()
|
||
privilege.GetSystemCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.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.String("T", "logon-type", "LOGON_NEW_CREDENTIALS", "logon type to use")
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
privilege.MakeTokenCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
|
||
// [ Websites ] ---------------------------------------------
|
||
|
||
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 {
|
||
con.Println()
|
||
websites.WebsitesCmd(ctx, con)
|
||
con.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 and all of its contents",
|
||
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 {
|
||
con.Println()
|
||
websites.WebsiteRmCmd(ctx, con)
|
||
con.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 specific 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 {
|
||
con.Println()
|
||
websites.WebsitesRmContent(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
websites.WebsitesAddContentCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
websites.WebsitesUpdateContentCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(websitesCmd)
|
||
|
||
// [ Screenshot ] ---------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.ScreenshotStr,
|
||
Help: "Take a screenshot",
|
||
LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("s", "save", "", "save to file (will overwrite if exists)")
|
||
f.Bool("X", "loot", false, "save output as loot")
|
||
f.String("n", "name", "", "name to assign loot (optional)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
screenshot.ScreenshotCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ Backdoor ] ---------------------------------------------
|
||
|
||
con.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 {
|
||
con.Println()
|
||
backdoor.BackdoorCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
|
||
// [ Beacons ] ---------------------------------------------
|
||
|
||
beaconsCmd := &grumble.Command{
|
||
Name: consts.BeaconsStr,
|
||
Help: "Manage beacons",
|
||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("k", "kill", "", "kill a beacon")
|
||
f.Bool("K", "kill-all", false, "kill all beacons")
|
||
f.Bool("F", "force", false, "force killing of the beacon")
|
||
f.String("f", "filter", "", "filter beacons by substring")
|
||
f.String("e", "filter-re", "", "filter beacons by regular expression")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
beacons.BeaconsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
}
|
||
beaconsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Remove a beacon",
|
||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.RmStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
beacons.BeaconsRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
beaconsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.WatchStr,
|
||
Help: "Watch your beacons",
|
||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
beacons.BeaconsWatchCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
beaconsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.PruneStr,
|
||
Help: "Prune stale beacons automatically",
|
||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("d", "duration", "1h", "duration to prune beacons that have missed their last checkin")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
beacons.BeaconsPruneCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
con.App.AddCommand(beaconsCmd)
|
||
|
||
// [ Environment ] ---------------------------------------------
|
||
|
||
envCmd := &grumble.Command{
|
||
Name: consts.EnvStr,
|
||
Help: "List environment variables",
|
||
LongHelp: help.GetHelpFor([]string{consts.EnvStr}),
|
||
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 {
|
||
con.Println()
|
||
environment.EnvGetCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
envCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SetStr,
|
||
Help: "Set environment variables",
|
||
LongHelp: help.GetHelpFor([]string{consts.EnvStr, consts.SetStr}),
|
||
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 {
|
||
con.Println()
|
||
environment.EnvSetCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
envCmd.AddCommand(&grumble.Command{
|
||
Name: consts.UnsetStr,
|
||
Help: "Clear environment variables",
|
||
LongHelp: help.GetHelpFor([]string{consts.EnvStr, consts.UnsetStr}),
|
||
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 {
|
||
con.Println()
|
||
environment.EnvUnsetCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(envCmd)
|
||
|
||
// [ Licenses ] ---------------------------------------------
|
||
|
||
con.App.AddCommand(&grumble.Command{
|
||
Name: consts.LicensesStr,
|
||
Help: "Open source licenses",
|
||
LongHelp: help.GetHelpFor([]string{consts.LicensesStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
con.Println(licenses.All)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
|
||
// [ Registry ] ---------------------------------------------
|
||
|
||
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 {
|
||
con.Println()
|
||
registry.RegReadCmd(ctx, con)
|
||
con.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", "registry 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 {
|
||
con.Println()
|
||
registry.RegWriteCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
registry.RegCreateKeyCmd(ctx, con)
|
||
con.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")
|
||
},
|
||
})
|
||
registryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RegistryDeleteKeyStr,
|
||
Help: "Remove a registry key",
|
||
LongHelp: help.GetHelpFor([]string{consts.RegistryDeleteKeyStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.String("registry-path", "registry path")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
registry.RegDeleteKeyCmd(ctx, con)
|
||
con.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 remove value from")
|
||
},
|
||
})
|
||
registryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RegistryListSubStr,
|
||
Help: "List the sub keys under a registry key",
|
||
LongHelp: help.GetHelpFor([]string{consts.RegistryListSubStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.String("registry-path", "registry path")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
registry.RegListSubKeysCmd(ctx, con)
|
||
con.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")
|
||
},
|
||
})
|
||
|
||
registryCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RegistryListValuesStr,
|
||
Help: "List the values for a registry key",
|
||
LongHelp: help.GetHelpFor([]string{consts.RegistryListValuesStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.String("registry-path", "registry path")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
registry.RegListValuesCmd(ctx, con)
|
||
con.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")
|
||
},
|
||
})
|
||
con.App.AddCommand(registryCmd)
|
||
|
||
// [ Reverse Port Forwarding ] --------------------------------------------------------------
|
||
|
||
rportfwdCmd := &grumble.Command{
|
||
Name: consts.RportfwdStr,
|
||
Help: "reverse port forwardings",
|
||
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
rportfwd.RportFwdListenersCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
}
|
||
rportfwdCmd.AddCommand(&grumble.Command{
|
||
Name: consts.AddStr,
|
||
Help: "Add and start reverse port forwarding",
|
||
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
rportfwd.StartRportFwdListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.String("r", "remote", "", "remote address <ip>:<port> connection is forwarded to")
|
||
f.String("b", "bind", "", "bind address <ip>:<port> implants listen on")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
rportfwdCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Stop and remove reverse port forwarding",
|
||
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
rportfwd.StopRportFwdListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Int("i", "id", 0, "id of portfwd to remove")
|
||
},
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
})
|
||
|
||
con.App.AddCommand(rportfwdCmd)
|
||
|
||
// [ Pivots ] --------------------------------------------------------------
|
||
|
||
pivotsCmd := &grumble.Command{
|
||
Name: consts.PivotsStr,
|
||
Help: "List pivots for active session",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.PivotsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
}
|
||
con.App.AddCommand(pivotsCmd)
|
||
|
||
pivotsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.NamedPipeStr,
|
||
Help: "Start a named pipe pivot listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.NamedPipeStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("b", "bind", "", "name of the named pipe to bind pivot listener")
|
||
f.Bool("a", "allow-all", false, "allow all users to connect")
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.StartNamedPipeListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
pivotsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.TCPListenerStr,
|
||
Help: "Start a TCP pivot listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.TCPListenerStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("b", "bind", "", "remote interface to bind pivot listener")
|
||
f.Int("l", "lport", generate.DefaultTCPPivotPort, "tcp pivot listener port")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.StartTCPListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
pivotsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.StopStr,
|
||
Help: "Stop a pivot listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("i", "id", 0, "id of the pivot listener to stop")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.StopPivotListenerCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
pivotsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.DetailsStr,
|
||
Help: "Get details of a pivot listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("i", "id", 0, "id of the pivot listener to stop")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.PivotDetailsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
pivotsCmd.AddCommand(&grumble.Command{
|
||
Name: "graph",
|
||
Help: "Get details of a pivot listener",
|
||
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, "graph"}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("i", "id", 0, "id of the pivot listener to stop")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
pivots.PivotsGraphCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
|
||
// [ WireGuard ] --------------------------------------------------------------
|
||
|
||
con.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 {
|
||
con.Println()
|
||
wireguard.WGConfigCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
wireguard.WGPortFwdListCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
}
|
||
wgPortFwdCmd.AddCommand(&grumble.Command{
|
||
Name: consts.AddStr,
|
||
Help: "Add a port forward from the WireGuard tun interface to a host on the target network",
|
||
LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.AddStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
wireguard.WGPortFwdAddCmd(ctx, con)
|
||
con.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: consts.RmStr,
|
||
Help: "Remove a port forward from the WireGuard tun interface",
|
||
LongHelp: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.RmStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.Int("id", "forwarder id")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
wireguard.WGPortFwdRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
})
|
||
con.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 {
|
||
con.Println()
|
||
wireguard.WGSocksListCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
}
|
||
wgSocksCmd.AddCommand(&grumble.Command{
|
||
Name: consts.StartStr,
|
||
Help: "Start a socks5 listener on the WireGuard tun interface",
|
||
LongHelp: help.GetHelpFor([]string{consts.WgSocksStr, consts.StartStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
wireguard.WGSocksStartCmd(ctx, con)
|
||
con.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: consts.StopStr,
|
||
Help: "Stop a socks5 listener on the WireGuard tun interface",
|
||
LongHelp: help.GetHelpFor([]string{consts.WgSocksStr, consts.StopStr}),
|
||
Args: func(a *grumble.Args) {
|
||
a.Int("id", "forwarder id")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
wireguard.WGSocksStopCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
})
|
||
con.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 {
|
||
con.Println()
|
||
portfwd.PortfwdCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
portfwd.PortfwdAddCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
portfwd.PortfwdRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
con.App.AddCommand(portfwdCmd)
|
||
|
||
// [ Socks ] --------------------------------------------------------------
|
||
|
||
socksCmd := &grumble.Command{
|
||
Name: consts.Socks5Str,
|
||
Help: "In-band SOCKS5 Proxy",
|
||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
socks.SocksCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
}
|
||
socksCmd.AddCommand(&grumble.Command{
|
||
Name: consts.StartStr,
|
||
Help: "Start an in-band SOCKS5 proxy",
|
||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("H", "host", "127.0.0.1", "Bind a Socks5 Host")
|
||
f.String("P", "port", "1081", "Bind a Socks5 Port")
|
||
f.String("u", "user", "", "socks5 auth username (will generate random password)")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
socks.SocksStartCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
socksCmd.AddCommand(&grumble.Command{
|
||
Name: consts.StopStr,
|
||
Help: "Stop a SOCKS5 proxy",
|
||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
|
||
f.Uint64("i", "id", 0, "id of portfwd to remove")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
socks.SocksStopCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
})
|
||
con.App.AddCommand(socksCmd)
|
||
|
||
// [ 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 {
|
||
con.Println()
|
||
monitor.MonitorStartCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
monitorCmd.AddCommand(&grumble.Command{
|
||
Name: "stop",
|
||
Help: "Stop the monitoring loops",
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
monitor.MonitorStopCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
con.App.AddCommand(monitorCmd)
|
||
|
||
// [ 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 {
|
||
con.Println()
|
||
loot.LootCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
loot.LootAddLocalCmd(ctx, con)
|
||
con.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 file path on the remote host 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 {
|
||
con.Println()
|
||
loot.LootAddRemoteCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
loot.LootAddCredentialCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
loot.LootRenameCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
lootCmd.AddCommand(&grumble.Command{
|
||
Name: consts.FetchStr,
|
||
Help: "Fetch a piece of loot from the server's loot store",
|
||
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.FetchStr}),
|
||
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 {
|
||
con.Println()
|
||
loot.LootFetchCmd(ctx, con)
|
||
con.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 {
|
||
con.Println()
|
||
loot.LootRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(lootCmd)
|
||
|
||
// [ Hosts ] --------------------------------------------------------------
|
||
hostsCmd := &grumble.Command{
|
||
Name: consts.HostsStr,
|
||
Help: "Manage the database of hosts",
|
||
LongHelp: help.GetHelpFor([]string{consts.HostsStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
hosts.HostsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
hostsCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Remove a host from the database",
|
||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.RmStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
hosts.HostsRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
iocCmd := &grumble.Command{
|
||
Name: consts.IOCStr,
|
||
Help: "Manage tracked IOCs on a given host",
|
||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
hosts.HostsIOCCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
iocCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Delete IOCs from the database",
|
||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr, consts.RmStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
hosts.HostsIOCRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
hostsCmd.AddCommand(iocCmd)
|
||
con.App.AddCommand(hostsCmd)
|
||
|
||
// [ Reactions ] -----------------------------------------------------------------
|
||
|
||
reactionCmd := &grumble.Command{
|
||
Name: consts.ReactionStr,
|
||
Help: "Manage automatic reactions to events",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReactionStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reaction.ReactionCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
}
|
||
reactionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SetStr,
|
||
Help: "Set a reaction to an event",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReactionStr, consts.SetStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("e", "event", "", "specify the event type to react to")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reaction.ReactionSetCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
reactionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.UnsetStr,
|
||
Help: "Unset an existing reaction",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReactionStr, consts.UnsetStr}),
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("i", "id", 0, "the id of the reaction to remove")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reaction.ReactionUnsetCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
reactionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.SaveStr,
|
||
Help: "Save current reactions to disk",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReactionStr, consts.SaveStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reaction.ReactionSaveCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
reactionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.ReloadStr,
|
||
Help: "Reload reactions from disk, replaces the running configuration",
|
||
LongHelp: help.GetHelpFor([]string{consts.ReactionStr, consts.ReloadStr}),
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
reaction.ReactionReloadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
})
|
||
con.App.AddCommand(reactionCmd)
|
||
|
||
// [ DLL Hijack ] -----------------------------------------------------------------
|
||
|
||
dllhijackCmd := &grumble.Command{
|
||
Name: consts.DLLHijackStr,
|
||
Help: "Plant a DLL for a hijack scenario",
|
||
LongHelp: help.GetHelpFor([]string{consts.DLLHijackStr}),
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
dllhijack.DllHijackCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("target-path", "Path to upload the DLL to on the remote system")
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("r", "reference-path", "", "Path to the reference DLL on the remote system")
|
||
f.String("R", "reference-file", "", "Path to the reference DLL on the local system")
|
||
f.String("f", "file", "", "Local path to the DLL to plant for the hijack")
|
||
f.String("p", "profile", "", "Profile name to use as a base DLL")
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
}
|
||
con.App.AddCommand(dllhijackCmd)
|
||
|
||
// [ Get Privs ] -----------------------------------------------------------------
|
||
getprivsCmd := &grumble.Command{
|
||
Name: consts.GetPrivsStr,
|
||
Help: "Get current privileges (Windows only)",
|
||
LongHelp: help.GetHelpFor([]string{consts.GetPrivsStr}),
|
||
HelpGroup: consts.SliverWinHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
privilege.GetPrivsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
}
|
||
con.App.AddCommand(getprivsCmd)
|
||
|
||
// [ Extensions ] -----------------------------------------------------------------
|
||
extensionCmd := &grumble.Command{
|
||
Name: consts.ExtensionsStr,
|
||
Help: "Manage extensions",
|
||
LongHelp: help.GetHelpFor([]string{consts.ExtensionsStr}),
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
extensions.ExtensionsCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
}
|
||
|
||
extensionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.ListStr,
|
||
Help: "List extensions loaded in the current session or beacon",
|
||
LongHelp: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}),
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
extensions.ExtensionsListCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
|
||
extensionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.LoadStr,
|
||
Help: "Temporarily load an extension from a local directory",
|
||
LongHelp: help.GetHelpFor([]string{consts.ExtensionsStr, consts.LoadStr}),
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
extensions.ExtensionLoadCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("dir-path", "path to the extension directory")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return completers.LocalPathCompleter(prefix, args, con)
|
||
},
|
||
})
|
||
|
||
extensionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.InstallStr,
|
||
Help: "Install an extension from a local directory or .tar.gz file",
|
||
LongHelp: help.GetHelpFor([]string{consts.ExtensionsStr, consts.InstallStr}),
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
extensions.ExtensionsInstallCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("path", "path to the extension .tar.gz or directory")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return completers.LocalPathCompleter(prefix, args, con)
|
||
},
|
||
})
|
||
|
||
extensionCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Remove an installed extension",
|
||
LongHelp: help.GetHelpFor([]string{consts.ExtensionsStr, consts.RmStr}),
|
||
HelpGroup: consts.SliverHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
extensions.ExtensionsRemoveCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("name", "the command name of the extension to remove")
|
||
},
|
||
Completer: func(prefix string, args []string) []string {
|
||
return extensions.ExtensionsCommandNameCompleter(prefix, args, con)
|
||
},
|
||
})
|
||
|
||
con.App.AddCommand(extensionCmd)
|
||
|
||
// [ Prelude's Operator ] ------------------------------------------------------------
|
||
operatorCmd := &grumble.Command{
|
||
Name: consts.PreludeOperatorStr,
|
||
Help: "Manage connection to Prelude's Operator",
|
||
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
operator.OperatorCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
}
|
||
operatorCmd.AddCommand(&grumble.Command{
|
||
Name: consts.ConnectStr,
|
||
Help: "Connect with Prelude's Operator",
|
||
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
operator.ConnectCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.String("connection-string", "connection string to the Operator Host (e.g. 127.0.0.1:1234)")
|
||
},
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Bool("s", "skip-existing", false, "Do not add existing sessions as Operator Agents")
|
||
f.String("a", "aes-key", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption")
|
||
f.String("r", "range", "sliver", "Agents range")
|
||
},
|
||
})
|
||
con.App.AddCommand(operatorCmd)
|
||
|
||
// [ Curse Commands ] ------------------------------------------------------------
|
||
|
||
cursedCmd := &grumble.Command{
|
||
Name: consts.Cursed,
|
||
Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
}
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.RmStr,
|
||
Help: "Remove a Curse from a process",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
f.Bool("k", "kill", false, "kill the process after removing the curse")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.Int("bind-port", "bind port of the Cursed process to stop")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedRmCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CursedConsole,
|
||
Help: "Start a JavaScript console connected to a debug target",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)`")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedConsoleCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CursedChrome,
|
||
Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
|
||
f.Bool("R", "restore", true, "restore the user's session after process termination")
|
||
f.String("e", "exe", "", "chrome/chromium browser executable path (blank string = auto)")
|
||
f.String("u", "user-data", "", "user data directory (blank string = auto)")
|
||
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
|
||
f.Bool("k", "keep-alive", false, "keeps browser alive after last browser window closes")
|
||
f.Bool("H", "headless", false, "start browser process in headless mode")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.StringList("args", "additional chrome cli arguments", grumble.Default([]string{}))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedChromeCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CursedEdge,
|
||
Help: "Automatically inject a Cursed Chrome payload into a remote Edge extension",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
|
||
f.Bool("R", "restore", true, "restore the user's session after process termination")
|
||
f.String("e", "exe", "", "edge browser executable path (blank string = auto)")
|
||
f.String("u", "user-data", "", "user data directory (blank string = auto)")
|
||
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
|
||
f.Bool("k", "keep-alive", false, "keeps browser alive after last browser window closes")
|
||
f.Bool("H", "headless", false, "start browser process in headless mode")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.StringList("args", "additional edge cli arguments", grumble.Default([]string{}))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedEdgeCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CursedElectron,
|
||
Help: "Curse a remote Electron application",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("e", "exe", "", "remote electron executable absolute path")
|
||
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Args: func(a *grumble.Args) {
|
||
a.StringList("args", "additional electron cli arguments", grumble.Default([]string{}))
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedElectronCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.CursedCookies,
|
||
Help: "Dump all cookies from cursed process",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedCookies}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.String("s", "save", "", "save to file")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedCookiesCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
cursedCmd.AddCommand(&grumble.Command{
|
||
Name: consts.ScreenshotStr,
|
||
Help: "Take a screenshot of a cursed process debug target",
|
||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int64("q", "quality", 100, "screenshot quality (1 - 100)")
|
||
f.String("s", "save", "", "save to file")
|
||
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
cursed.CursedScreenshotCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
})
|
||
con.App.AddCommand(cursedCmd)
|
||
|
||
// [ Builders ] ---------------------------------------------
|
||
buildersCmd := &grumble.Command{
|
||
Name: consts.BuildersStr,
|
||
Help: "List external builders",
|
||
LongHelp: help.GetHelpFor([]string{consts.BuildersStr}),
|
||
HelpGroup: consts.GenericHelpGroup,
|
||
Flags: func(f *grumble.Flags) {
|
||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||
},
|
||
Run: func(ctx *grumble.Context) error {
|
||
con.Println()
|
||
builders.BuildersCmd(ctx, con)
|
||
con.Println()
|
||
return nil
|
||
},
|
||
}
|
||
con.App.AddCommand(buildersCmd)
|
||
}
|