aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan McNulty <bryanmcnulty@protonmail.com>2025-04-25 10:44:52 -0500
committerBryan McNulty <bryanmcnulty@protonmail.com>2025-04-25 10:44:52 -0500
commit865b523bdd4b006661ef8fbf76d24e4b7ad1cf8e (patch)
treec71109362f375cfecdacc96fcb90da982109de0a
parentc523a600769c4f043cbc52e0493ab47c0144062f (diff)
downloadgoexec-0.1.1.tar.gz
goexec-0.1.1.zip
Small cosmetic changes in Cobra cmdsv0.1.1
-rw-r--r--cmd/dcom.go113
-rw-r--r--cmd/root.go376
-rw-r--r--cmd/scmr.go391
-rw-r--r--cmd/tsch.go397
-rw-r--r--cmd/wmi.go231
5 files changed, 756 insertions, 752 deletions
diff --git a/cmd/dcom.go b/cmd/dcom.go
index 6d2643b..89fac18 100644
--- a/cmd/dcom.go
+++ b/cmd/dcom.go
@@ -1,79 +1,80 @@
package cmd
import (
- "context"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- dcomexec "github.com/FalconOpsLLC/goexec/pkg/goexec/dcom"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/spf13/cobra"
+ "context"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ dcomexec "github.com/FalconOpsLLC/goexec/pkg/goexec/dcom"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/spf13/cobra"
)
func dcomCmdInit() {
- cmdFlags[dcomCmd] = []*flagSet{
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
- dcomMmcCmdInit()
+ cmdFlags[dcomCmd] = []*flagSet{
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+ dcomMmcCmdInit()
- dcomCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
- dcomCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
- dcomCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
- dcomCmd.AddCommand(dcomMmcCmd)
+ dcomCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
+ dcomCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
+ dcomCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
+ dcomCmd.AddCommand(dcomMmcCmd)
}
func dcomMmcCmdInit() {
- dcomMmcExecFlags := newFlagSet("Execution")
+ dcomMmcExecFlags := newFlagSet("Execution")
- registerExecutionFlags(dcomMmcExecFlags.Flags)
- registerExecutionOutputFlags(dcomMmcExecFlags.Flags)
+ registerExecutionFlags(dcomMmcExecFlags.Flags)
+ registerExecutionOutputFlags(dcomMmcExecFlags.Flags)
- dcomMmcExecFlags.Flags.StringVar(&dcomMmc.WorkingDirectory, "directory", `C:\`, "Working `directory`")
- dcomMmcExecFlags.Flags.StringVar(&dcomMmc.WindowState, "window", "Minimized", "Window state")
+ dcomMmcExecFlags.Flags.StringVar(&dcomMmc.WorkingDirectory, "directory", `C:\`, "Working `directory`")
+ dcomMmcExecFlags.Flags.StringVar(&dcomMmc.WindowState, "window", "Minimized", "Window state")
- cmdFlags[dcomMmcCmd] = []*flagSet{
- dcomMmcExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
+ cmdFlags[dcomMmcCmd] = []*flagSet{
+ dcomMmcExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
- dcomMmcCmd.Flags().AddFlagSet(dcomMmcExecFlags.Flags)
+ dcomMmcCmd.Flags().AddFlagSet(dcomMmcExecFlags.Flags)
}
var (
- dcomMmc dcomexec.DcomMmc
+ dcomMmc dcomexec.DcomMmc
- dcomCmd = &cobra.Command{
- Use: "dcom",
- Short: "Execute with Distributed Component Object Model (MS-DCOM)",
- GroupID: "module",
- Args: cobra.NoArgs,
- }
+ dcomCmd = &cobra.Command{
+ Use: "dcom",
+ Short: "Execute with Distributed Component Object Model (MS-DCOM)",
+ Long: `Description:
+ The dcom module uses exposed Distributed Component Object Model (DCOM) objects to spawn processes.`,
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
- dcomMmcCmd = &cobra.Command{
- Use: "mmc [target]",
- Short: "Execute with the DCOM MMC20.Application object",
- Long: `Description:
+ dcomMmcCmd = &cobra.Command{
+ Use: "mmc [target]",
+ Short: "Execute with the DCOM MMC20.Application object",
+ Long: `Description:
The mmc method uses the exposed MMC20.Application object to call Document.ActiveView.ShellExec,
- and ultimately spawn a process on the remote host.
-`,
- Args: args(
- argsRpcClient("host"),
- argsOutput("smb"),
- ),
- Run: func(cmd *cobra.Command, args []string) {
- dcomMmc.Dcom.Client = &rpcClient
- dcomMmc.IO = exec
+ and ultimately spawn a process on the remote host.`,
+ Args: args(
+ argsRpcClient("host"),
+ argsOutput("smb"),
+ ),
+ Run: func(cmd *cobra.Command, args []string) {
+ dcomMmc.Dcom.Client = &rpcClient
+ dcomMmc.IO = exec
- ctx := log.With().
- Str("module", "dcom").
- Str("method", "mmc").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+ ctx := log.With().
+ Str("module", "dcom").
+ Str("method", "mmc").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
- if err := goexec.ExecuteCleanMethod(ctx, &dcomMmc, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ if err := goexec.ExecuteCleanMethod(ctx, &dcomMmc, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
)
diff --git a/cmd/root.go b/cmd/root.go
index a648b32..33b0116 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,25 +1,25 @@
package cmd
import (
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
- "github.com/FalconOpsLLC/goexec/pkg/goexec/smb"
- "github.com/RedTeamPentesting/adauth"
- "github.com/google/uuid"
- "github.com/oiweiwei/go-msrpc/ssp"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/rs/zerolog"
- "github.com/spf13/cobra"
- "github.com/spf13/pflag"
- "golang.org/x/term"
- "io"
- "os"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec/smb"
+ "github.com/RedTeamPentesting/adauth"
+ "github.com/google/uuid"
+ "github.com/oiweiwei/go-msrpc/ssp"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/rs/zerolog"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+ "golang.org/x/term"
+ "io"
+ "os"
)
type flagSet struct {
- Label string
- Flags *pflag.FlagSet
+ Label string
+ Flags *pflag.FlagSet
}
const helpTemplate = `Usage:{{if .Runnable}}
@@ -51,47 +51,47 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
`
var (
- cmdFlags = make(map[*cobra.Command][]*flagSet)
-
- defaultAuthFlags, defaultLogFlags, defaultNetRpcFlags *flagSet
-
- returnCode int
-
- // === IO ===
- stageFilePath string
- outputMethod string
- outputPath string
- // ==========
-
- // === Logging ===
- logJson bool // Log output in JSON lines
- logDebug bool // Output debug log messages
- logQuiet bool // Suppress logging output
- logOutput string // Log output file
- logLevel zerolog.Level = zerolog.InfoLevel
- logFile io.WriteCloser = os.Stderr
- log zerolog.Logger
- // ===============
-
- // === Network ===
- proxy string
- rpcClient dce.Client
- smbClient smb.Client
- // ===============
-
- exec = goexec.ExecutionIO{
- Input: new(goexec.ExecutionInput),
- Output: new(goexec.ExecutionOutput),
- }
-
- adAuthOpts *adauth.Options
- credential *adauth.Credential
- target *adauth.Target
-
- rootCmd = &cobra.Command{
- Use: "goexec",
- Short: `goexec - Windows remote execution multitool`,
- Long: `
+ cmdFlags = make(map[*cobra.Command][]*flagSet)
+
+ defaultAuthFlags, defaultLogFlags, defaultNetRpcFlags *flagSet
+
+ returnCode int
+
+ // === IO ===
+ stageFilePath string
+ outputMethod string
+ outputPath string
+ // ==========
+
+ // === Logging ===
+ logJson bool // Log output in JSON lines
+ logDebug bool // Output debug log messages
+ logQuiet bool // Suppress logging output
+ logOutput string // Log output file
+ logLevel zerolog.Level = zerolog.InfoLevel
+ logFile io.WriteCloser = os.Stderr
+ log zerolog.Logger
+ // ===============
+
+ // === Network ===
+ proxy string
+ rpcClient dce.Client
+ smbClient smb.Client
+ // ===============
+
+ exec = goexec.ExecutionIO{
+ Input: new(goexec.ExecutionInput),
+ Output: new(goexec.ExecutionOutput),
+ }
+
+ adAuthOpts *adauth.Options
+ credential *adauth.Credential
+ target *adauth.Target
+
+ rootCmd = &cobra.Command{
+ Use: "goexec",
+ Short: `goexec - Windows remote execution multitool`,
+ Long: `
___ ___ ___ _ _ ___ ___
| . | . | -_|_'_| -_| _|
|_ |___|___|_,_|___|___|
@@ -104,144 +104,144 @@ Authors: FalconOps LLC (@FalconOpsLLC),
while providing an extremely flexible CLI and a strong focus on OPSEC.
`,
- PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
-
- // Parse logging options
- {
- if logOutput != "" {
- logFile, err = os.OpenFile(logOutput, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
- if err != nil {
- return
- }
- logJson = true
- }
- if logQuiet {
- logLevel = zerolog.ErrorLevel
- } else if logDebug {
- logLevel = zerolog.DebugLevel
- }
- if logJson {
- log = zerolog.New(logFile).With().Timestamp().Logger()
- } else {
- log = zerolog.New(zerolog.ConsoleWriter{Out: logFile}).With().Timestamp().Logger()
- }
- log = log.Level(logLevel)
- }
-
- if proxy != "" {
- rpcClient.Proxy = proxy
- smbClient.Proxy = proxy
- }
-
- if outputPath != "" {
- if outputMethod == "smb" {
- if exec.Output.RemotePath == "" {
- exec.Output.RemotePath = `C:\Windows\Temp\` + uuid.NewString()
- }
- exec.Output.Provider = &smb.OutputFileFetcher{
- Client: &smbClient,
- Share: `ADMIN$`, // TODO: dynamic
- SharePath: `C:\Windows`,
- File: exec.Output.RemotePath,
- DeleteOutputFile: !exec.Output.NoDelete,
- }
- }
- }
- return
- },
-
- PersistentPostRun: func(cmd *cobra.Command, args []string) {
- if err := logFile.Close(); err != nil {
- // ...
- }
- if err := exec.Input.StageFile.Close(); err != nil {
- // ...
- }
- },
- }
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
+
+ // Parse logging options
+ {
+ if logOutput != "" {
+ logFile, err = os.OpenFile(logOutput, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ return
+ }
+ logJson = true
+ }
+ if logQuiet {
+ logLevel = zerolog.ErrorLevel
+ } else if logDebug {
+ logLevel = zerolog.DebugLevel
+ }
+ if logJson {
+ log = zerolog.New(logFile).With().Timestamp().Logger()
+ } else {
+ log = zerolog.New(zerolog.ConsoleWriter{Out: logFile}).With().Timestamp().Logger()
+ }
+ log = log.Level(logLevel)
+ }
+
+ if proxy != "" {
+ rpcClient.Proxy = proxy
+ smbClient.Proxy = proxy
+ }
+
+ if outputPath != "" {
+ if outputMethod == "smb" {
+ if exec.Output.RemotePath == "" {
+ exec.Output.RemotePath = `C:\Windows\Temp\` + uuid.NewString()
+ }
+ exec.Output.Provider = &smb.OutputFileFetcher{
+ Client: &smbClient,
+ Share: `ADMIN$`, // TODO: dynamic
+ SharePath: `C:\Windows`,
+ File: exec.Output.RemotePath,
+ DeleteOutputFile: !exec.Output.NoDelete,
+ }
+ }
+ }
+ return
+ },
+
+ PersistentPostRun: func(cmd *cobra.Command, args []string) {
+ if err := logFile.Close(); err != nil {
+ // ...
+ }
+ if err := exec.Input.StageFile.Close(); err != nil {
+ // ...
+ }
+ },
+ }
)
func newFlagSet(name string) *flagSet {
- flags := pflag.NewFlagSet(name, pflag.ExitOnError)
- flags.SortFlags = false
- return &flagSet{
- Label: name,
- Flags: flags,
- }
+ flags := pflag.NewFlagSet(name, pflag.ExitOnError)
+ flags.SortFlags = false
+ return &flagSet{
+ Label: name,
+ Flags: flags,
+ }
}
func init() {
- // Auth init
- {
- gssapi.AddMechanism(ssp.SPNEGO)
- gssapi.AddMechanism(ssp.NTLM)
- gssapi.AddMechanism(ssp.KRB5)
- }
-
- // Cobra init
- {
- cobra.EnableCommandSorting = false
- {
- defaultNetRpcFlags = newFlagSet("Network")
- registerNetworkFlags(defaultNetRpcFlags.Flags)
- }
- {
- defaultLogFlags = newFlagSet("Logging")
- registerLoggingFlags(defaultLogFlags.Flags)
- }
- {
- defaultAuthFlags = newFlagSet("Authentication")
- adAuthOpts = &adauth.Options{
- Debug: log.Debug().Msgf,
- }
- adAuthOpts.RegisterFlags(defaultAuthFlags.Flags)
- }
-
- modules := &cobra.Group{
- ID: "module",
- Title: "Execution Commands:",
- }
- rootCmd.AddGroup(modules)
-
- cmdFlags[rootCmd] = []*flagSet{
- defaultLogFlags,
- defaultAuthFlags,
- }
-
- cobra.AddTemplateFunc("flags", func(fs *pflag.FlagSet) string {
- if width, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil {
- return fs.FlagUsagesWrapped(width - 1)
- }
- return fs.FlagUsagesWrapped(80 - 1)
- })
-
- cobra.AddTemplateFunc("cmdFlags", func(cmd *cobra.Command) []*flagSet {
- return cmdFlags[cmd]
- })
-
- rootCmd.InitDefaultVersionFlag()
- rootCmd.InitDefaultHelpCmd()
- rootCmd.SetHelpTemplate("{{if (ne .Long \"\")}}{{.Long}}\n{{end}}" + helpTemplate)
- rootCmd.SetUsageTemplate(helpTemplate)
-
- // Modules init
- {
- dcomCmdInit()
- rootCmd.AddCommand(dcomCmd)
- wmiCmdInit()
- rootCmd.AddCommand(wmiCmd)
- scmrCmdInit()
- rootCmd.AddCommand(scmrCmd)
- tschCmdInit()
- rootCmd.AddCommand(tschCmd)
- }
- }
+ // Auth init
+ {
+ gssapi.AddMechanism(ssp.SPNEGO)
+ gssapi.AddMechanism(ssp.NTLM)
+ gssapi.AddMechanism(ssp.KRB5)
+ }
+
+ // Cobra init
+ {
+ cobra.EnableCommandSorting = false
+ {
+ defaultNetRpcFlags = newFlagSet("Network")
+ registerNetworkFlags(defaultNetRpcFlags.Flags)
+ }
+ {
+ defaultLogFlags = newFlagSet("Logging")
+ registerLoggingFlags(defaultLogFlags.Flags)
+ }
+ {
+ defaultAuthFlags = newFlagSet("Authentication")
+ adAuthOpts = &adauth.Options{
+ Debug: log.Debug().Msgf,
+ }
+ adAuthOpts.RegisterFlags(defaultAuthFlags.Flags)
+ }
+
+ modules := &cobra.Group{
+ ID: "module",
+ Title: "Execution Commands:",
+ }
+ rootCmd.AddGroup(modules)
+
+ cmdFlags[rootCmd] = []*flagSet{
+ defaultLogFlags,
+ defaultAuthFlags,
+ }
+
+ cobra.AddTemplateFunc("flags", func(fs *pflag.FlagSet) string {
+ if width, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil {
+ return fs.FlagUsagesWrapped(width - 1)
+ }
+ return fs.FlagUsagesWrapped(80 - 1)
+ })
+
+ cobra.AddTemplateFunc("cmdFlags", func(cmd *cobra.Command) []*flagSet {
+ return cmdFlags[cmd]
+ })
+
+ rootCmd.InitDefaultVersionFlag()
+ rootCmd.InitDefaultHelpCmd()
+ rootCmd.SetHelpTemplate("{{if (ne .Long \"\")}}{{.Long}}\n\n{{end}}" + helpTemplate)
+ rootCmd.SetUsageTemplate(helpTemplate)
+
+ // Modules init
+ {
+ dcomCmdInit()
+ rootCmd.AddCommand(dcomCmd)
+ wmiCmdInit()
+ rootCmd.AddCommand(wmiCmd)
+ scmrCmdInit()
+ rootCmd.AddCommand(scmrCmd)
+ tschCmdInit()
+ rootCmd.AddCommand(tschCmd)
+ }
+ }
}
func Execute() {
- if err := rootCmd.Execute(); err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
- os.Exit(returnCode)
+ if err := rootCmd.Execute(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ os.Exit(returnCode)
}
diff --git a/cmd/scmr.go b/cmd/scmr.go
index 4edcf22..23d9272 100644
--- a/cmd/scmr.go
+++ b/cmd/scmr.go
@@ -1,217 +1,222 @@
package cmd
import (
- "context"
- "github.com/FalconOpsLLC/goexec/internal/util"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/spf13/cobra"
+ "context"
+ "github.com/FalconOpsLLC/goexec/internal/util"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/spf13/cobra"
- scmrexec "github.com/FalconOpsLLC/goexec/pkg/goexec/scmr"
+ scmrexec "github.com/FalconOpsLLC/goexec/pkg/goexec/scmr"
)
func scmrCmdInit() {
- cmdFlags[scmrCmd] = []*flagSet{
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
- scmrCreateCmdInit()
- scmrChangeCmdInit()
- scmrDeleteCmdInit()
-
- scmrCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
- scmrCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
- scmrCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
- scmrCmd.AddCommand(scmrCreateCmd, scmrChangeCmd, scmrDeleteCmd)
+ cmdFlags[scmrCmd] = []*flagSet{
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+ scmrCreateCmdInit()
+ scmrChangeCmdInit()
+ scmrDeleteCmdInit()
+
+ scmrCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
+ scmrCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
+ scmrCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
+ scmrCmd.AddCommand(scmrCreateCmd, scmrChangeCmd, scmrDeleteCmd)
}
func scmrCreateCmdInit() {
- scmrCreateFlags := newFlagSet("Service")
-
- scmrCreateFlags.Flags.StringVarP(&scmrCreate.DisplayName, "display-name", "n", "", "Display name of service to create")
- scmrCreateFlags.Flags.StringVarP(&scmrCreate.ServiceName, "service", "s", "", "Name of service to create")
- scmrCreateFlags.Flags.BoolVar(&scmrCreate.NoDelete, "no-delete", false, "Don't delete service after execution")
- scmrCreateFlags.Flags.BoolVar(&scmrCreate.NoStart, "no-start", false, "Don't start service")
-
- scmrCreateExecFlags := newFlagSet("Execution")
-
- // TODO: SCMR output
- //registerExecutionOutputFlags(scmrCreateExecFlags.Flags)
-
- scmrCreateExecFlags.Flags.StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to a remote Windows executable")
- scmrCreateExecFlags.Flags.StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to the executable")
-
- scmrCreateCmd.Flags().AddFlagSet(scmrCreateFlags.Flags)
- scmrCreateCmd.Flags().AddFlagSet(scmrCreateExecFlags.Flags)
-
- cmdFlags[scmrCreateCmd] = []*flagSet{
- scmrCreateExecFlags,
- scmrCreateFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
-
- // Constraints
- {
- //scmrCreateCmd.MarkFlagsMutuallyExclusive("no-delete", "no-start")
- if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil {
- panic(err)
- }
- }
+ scmrCreateFlags := newFlagSet("Service")
+
+ scmrCreateFlags.Flags.StringVarP(&scmrCreate.DisplayName, "display-name", "n", "", "Display name of service to create")
+ scmrCreateFlags.Flags.StringVarP(&scmrCreate.ServiceName, "service", "s", "", "Name of service to create")
+ scmrCreateFlags.Flags.BoolVar(&scmrCreate.NoDelete, "no-delete", false, "Don't delete service after execution")
+ scmrCreateFlags.Flags.BoolVar(&scmrCreate.NoStart, "no-start", false, "Don't start service")
+
+ scmrCreateExecFlags := newFlagSet("Execution")
+
+ // TODO: SCMR output
+ //registerExecutionOutputFlags(scmrCreateExecFlags.Flags)
+
+ scmrCreateExecFlags.Flags.StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to a remote Windows executable")
+ scmrCreateExecFlags.Flags.StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to the executable")
+
+ scmrCreateCmd.Flags().AddFlagSet(scmrCreateFlags.Flags)
+ scmrCreateCmd.Flags().AddFlagSet(scmrCreateExecFlags.Flags)
+
+ cmdFlags[scmrCreateCmd] = []*flagSet{
+ scmrCreateExecFlags,
+ scmrCreateFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+
+ // Constraints
+ {
+ //scmrCreateCmd.MarkFlagsMutuallyExclusive("no-delete", "no-start")
+ if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil {
+ panic(err)
+ }
+ }
}
func scmrChangeCmdInit() {
- scmrChangeFlags := newFlagSet("Service Control")
-
- scmrChangeFlags.Flags.StringVarP(&scmrChange.ServiceName, "service-name", "s", "", "Name of service to modify")
- scmrChangeFlags.Flags.BoolVar(&scmrChange.NoStart, "no-start", false, "Don't start service")
-
- scmrChangeExecFlags := newFlagSet("Execution")
-
- scmrChangeExecFlags.Flags.StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to remote Windows executable")
- scmrChangeExecFlags.Flags.StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to executable")
-
- // TODO: SCMR output
- //registerExecutionOutputFlags(scmrChangeExecFlags.Flags)
- //registerStageFlags(scmrChangeExecFlags.Flags)
-
- cmdFlags[scmrChangeCmd] = []*flagSet{
- scmrChangeFlags,
- scmrChangeExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
-
- scmrChangeCmd.Flags().AddFlagSet(scmrChangeFlags.Flags)
- scmrChangeCmd.Flags().AddFlagSet(scmrChangeExecFlags.Flags)
-
- // Constraints
- {
- if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil {
- panic(err)
- }
- if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil {
- panic(err)
- }
- }
+ scmrChangeFlags := newFlagSet("Service Control")
+
+ scmrChangeFlags.Flags.StringVarP(&scmrChange.ServiceName, "service-name", "s", "", "Name of service to modify")
+ scmrChangeFlags.Flags.BoolVar(&scmrChange.NoStart, "no-start", false, "Don't start service")
+
+ scmrChangeExecFlags := newFlagSet("Execution")
+
+ scmrChangeExecFlags.Flags.StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to remote Windows executable")
+ scmrChangeExecFlags.Flags.StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to executable")
+
+ // TODO: SCMR output
+ //registerExecutionOutputFlags(scmrChangeExecFlags.Flags)
+ //registerStageFlags(scmrChangeExecFlags.Flags)
+
+ cmdFlags[scmrChangeCmd] = []*flagSet{
+ scmrChangeFlags,
+ scmrChangeExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+
+ scmrChangeCmd.Flags().AddFlagSet(scmrChangeFlags.Flags)
+ scmrChangeCmd.Flags().AddFlagSet(scmrChangeExecFlags.Flags)
+
+ // Constraints
+ {
+ if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil {
+ panic(err)
+ }
+ if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil {
+ panic(err)
+ }
+ }
}
func scmrDeleteCmdInit() {
- scmrDeleteFlags := newFlagSet("Service Control")
- scmrDeleteFlags.Flags.StringVarP(&scmrDelete.ServiceName, "service-name", "s", scmrDelete.ServiceName, "Name of service to delete")
+ scmrDeleteFlags := newFlagSet("Service Control")
+ scmrDeleteFlags.Flags.StringVarP(&scmrDelete.ServiceName, "service-name", "s", scmrDelete.ServiceName, "Name of service to delete")
- cmdFlags[scmrDeleteCmd] = []*flagSet{
- scmrDeleteFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
+ cmdFlags[scmrDeleteCmd] = []*flagSet{
+ scmrDeleteFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
- scmrDeleteCmd.Flags().AddFlagSet(scmrDeleteFlags.Flags)
+ scmrDeleteCmd.Flags().AddFlagSet(scmrDeleteFlags.Flags)
- if err := scmrDeleteCmd.MarkFlagRequired("service-name"); err != nil {
- panic(err)
- }
+ if err := scmrDeleteCmd.MarkFlagRequired("service-name"); err != nil {
+ panic(err)
+ }
}
var (
- scmrCreate = scmrexec.ScmrCreate{}
- scmrChange = scmrexec.ScmrChange{}
- scmrDelete = scmrexec.ScmrDelete{}
-
- scmrCmd = &cobra.Command{
- Use: "scmr",
- Short: "Execute with Service Control Manager Remote (MS-SCMR)",
- GroupID: "module",
- Args: cobra.NoArgs,
- }
-
- scmrCreateCmd = &cobra.Command{
- Use: "create [target]",
- Short: "Spawn a remote process by creating & running a Windows service",
- Long: `Description:
+ scmrCreate = scmrexec.ScmrCreate{}
+ scmrChange = scmrexec.ScmrChange{}
+ scmrDelete = scmrexec.ScmrDelete{}
+
+ scmrCmd = &cobra.Command{
+ Use: "scmr",
+ Short: "Execute with Service Control Manager Remote (MS-SCMR)",
+ Long: `Description:
+ The SCMR module works a lot like Impacket's smbexec.py, but it provides additional RPC transports
+ to evade network monitoring or firewall rules, and some minor OPSEC improvements overall.`,
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
+
+ scmrCreateCmd = &cobra.Command{
+ Use: "create [target]",
+ Short: "Spawn a remote process by creating & running a Windows service",
+ Long: `Description:
The create method calls RCreateServiceW to create a new Windows service on the
- remote target with the provided executable & arguments as the lpBinaryPathName
-
-References:
- - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e
-`,
- Args: args(
- argsRpcClient("cifs"),
- argsSmbClient(),
- ),
-
- Run: func(cmd *cobra.Command, args []string) {
- scmrCreate.Client = &rpcClient
- scmrCreate.IO = exec
-
- log = log.With().
- Str("module", "scmr").
- Str("method", "create").
- Logger()
-
- // Warnings
- {
- if scmrCreate.ServiceName == "" {
- log.Warn().Msg("No service name was provided. Using a random string")
- scmrCreate.ServiceName = util.RandomString()
- }
- if scmrCreate.NoDelete {
- log.Warn().Msg("Service will not be deleted after execution")
- }
- if scmrCreate.DisplayName == "" {
- log.Debug().Msg("No display name specified, using service name as display name")
- scmrCreate.DisplayName = scmrCreate.ServiceName
- }
- }
-
- ctx := log.WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &scmrCreate, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
-
- scmrChangeCmd = &cobra.Command{
- Use: "change [target]",
- Short: "Change an existing Windows service to spawn an arbitrary process",
- Args: argsRpcClient("cifs"),
-
- Run: func(cmd *cobra.Command, args []string) {
- scmrChange.Client = &rpcClient
- scmrChange.IO = exec
-
- ctx := log.With().
- Str("module", "scmr").
- Str("method", "change").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &scmrChange, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
- scmrDeleteCmd = &cobra.Command{
- Use: "delete [target]",
- Short: "Delete an existing Windows service",
- Long: `TODO`,
-
- Args: argsRpcClient("cifs"),
- Run: func(cmd *cobra.Command, args []string) {
- scmrDelete.Client = &rpcClient
-
- ctx := log.With().
- Str("module", "scmr").
- Str("method", "delete").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanAuxiliaryMethod(ctx, &scmrDelete); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ remote target with the provided executable & arguments as the lpBinaryPathName`,
+ Args: args(
+ argsRpcClient("cifs"),
+ argsSmbClient(),
+ ),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ scmrCreate.Client = &rpcClient
+ scmrCreate.IO = exec
+
+ log = log.With().
+ Str("module", "scmr").
+ Str("method", "create").
+ Logger()
+
+ // Warnings
+ {
+ if scmrCreate.ServiceName == "" {
+ log.Warn().Msg("No service name was provided. Using a random string")
+ scmrCreate.ServiceName = util.RandomString()
+ }
+ if scmrCreate.NoDelete {
+ log.Warn().Msg("Service will not be deleted after execution")
+ }
+ if scmrCreate.DisplayName == "" {
+ log.Debug().Msg("No display name specified, using service name as display name")
+ scmrCreate.DisplayName = scmrCreate.ServiceName
+ }
+ }
+
+ ctx := log.WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &scmrCreate, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
+
+ scmrChangeCmd = &cobra.Command{
+ Use: "change [target]",
+ Short: "Change an existing Windows service to spawn an arbitrary process",
+ Long: `Description:
+ The change method executes programs by modifying existing Windows services
+ using the RChangeServiceConfigW method rather than calling RCreateServiceW
+ like scmr create. The modified service is restored to its original state
+ after execution`,
+ Args: argsRpcClient("cifs"),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ scmrChange.Client = &rpcClient
+ scmrChange.IO = exec
+
+ ctx := log.With().
+ Str("module", "scmr").
+ Str("method", "change").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &scmrChange, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
+ scmrDeleteCmd = &cobra.Command{
+ Use: "delete [target]",
+ Short: "Delete an existing Windows service",
+ Long: `Description:
+ The delete method will simply delete the provided service.`,
+
+ Args: argsRpcClient("cifs"),
+ Run: func(cmd *cobra.Command, args []string) {
+ scmrDelete.Client = &rpcClient
+
+ ctx := log.With().
+ Str("module", "scmr").
+ Str("method", "delete").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanAuxiliaryMethod(ctx, &scmrDelete); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
)
diff --git a/cmd/tsch.go b/cmd/tsch.go
index d9eee9a..ec3504f 100644
--- a/cmd/tsch.go
+++ b/cmd/tsch.go
@@ -1,232 +1,233 @@
package cmd
import (
- "context"
- "fmt"
- "github.com/FalconOpsLLC/goexec/internal/util"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- tschexec "github.com/FalconOpsLLC/goexec/pkg/goexec/tsch"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/spf13/cobra"
- "time"
+ "context"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/internal/util"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ tschexec "github.com/FalconOpsLLC/goexec/pkg/goexec/tsch"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/spf13/cobra"
+ "time"
)
func tschCmdInit() {
- cmdFlags[tschCmd] = []*flagSet{
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
- tschDemandCmdInit()
- tschCreateCmdInit()
- tschChangeCmdInit()
-
- tschCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
- tschCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
- tschCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
- tschCmd.AddCommand(tschDemandCmd, tschCreateCmd, tschChangeCmd)
+ cmdFlags[tschCmd] = []*flagSet{
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+ tschDemandCmdInit()
+ tschCreateCmdInit()
+ tschChangeCmdInit()
+
+ tschCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
+ tschCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
+ tschCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
+ tschCmd.AddCommand(tschDemandCmd, tschCreateCmd, tschChangeCmd)
}
func tschDemandCmdInit() {
- tschDemandFlags := newFlagSet("Task Scheduler")
+ tschDemandFlags := newFlagSet("Task Scheduler")
- tschDemandFlags.Flags.StringVarP(&tschTask, "task", "t", "", "Name or path of the new task")
- tschDemandFlags.Flags.Uint32Var(&tschDemand.SessionId, "session", 0, "Hijack existing session given the session ID")
- tschDemandFlags.Flags.StringVar(&tschDemand.UserSid, "sid", "S-1-5-18", "User SID to impersonate")
- tschDemandFlags.Flags.BoolVar(&tschDemand.NoDelete, "no-delete", false, "Don't delete task after execution")
+ tschDemandFlags.Flags.StringVarP(&tschTask, "task", "t", "", "Name or path of the new task")
+ tschDemandFlags.Flags.Uint32Var(&tschDemand.SessionId, "session", 0, "Hijack existing session given the session `ID`")
+ tschDemandFlags.Flags.StringVar(&tschDemand.UserSid, "sid", "S-1-5-18", "User `SID` to impersonate")
+ tschDemandFlags.Flags.BoolVar(&tschDemand.NoDelete, "no-delete", false, "Don't delete task after execution")
- tschDemandExecFlags := newFlagSet("Execution")
+ tschDemandExecFlags := newFlagSet("Execution")
- registerExecutionFlags(tschDemandExecFlags.Flags)
- registerExecutionOutputFlags(tschDemandExecFlags.Flags)
+ registerExecutionFlags(tschDemandExecFlags.Flags)
+ registerExecutionOutputFlags(tschDemandExecFlags.Flags)
- cmdFlags[tschDemandCmd] = []*flagSet{
- tschDemandFlags,
- tschDemandExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
+ cmdFlags[tschDemandCmd] = []*flagSet{
+ tschDemandFlags,
+ tschDemandExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
- tschDemandCmd.Flags().AddFlagSet(tschDemandFlags.Flags)
- tschDemandCmd.Flags().AddFlagSet(tschDemandExecFlags.Flags)
- tschDemandCmd.MarkFlagsOneRequired("exec", "command")
+ tschDemandCmd.Flags().AddFlagSet(tschDemandFlags.Flags)
+ tschDemandCmd.Flags().AddFlagSet(tschDemandExecFlags.Flags)
+ tschDemandCmd.MarkFlagsOneRequired("exec", "command")
}
func tschCreateCmdInit() {
- tschCreateFlags := newFlagSet("Task Scheduler")
-
- tschCreateFlags.Flags.StringVarP(&tschTask, "task", "t", "", "Name or path of the new task")
- tschCreateFlags.Flags.DurationVar(&tschCreate.StopDelay, "delay-stop", 5*time.Second, "Delay between task execution and termination. This won't stop the spawned process")
- tschCreateFlags.Flags.DurationVar(&tschCreate.StartDelay, "start-delay", 5*time.Second, "Delay between task registration and execution")
- //tschCreateFlags.Flags.DurationVar(&tschCreate.DeleteDelay, "delete-delay", 0*time.Second, "Delay between task termination and deletion")
- tschCreateFlags.Flags.BoolVar(&tschCreate.NoDelete, "no-delete", false, "Don't delete task after execution")
- tschCreateFlags.Flags.BoolVar(&tschCreate.CallDelete, "call-delete", false, "Directly call SchRpcDelete to delete task")
- tschCreateFlags.Flags.StringVar(&tschCreate.UserSid, "sid", "S-1-5-18", "User `SID` to impersonate")
-
- tschCreateExecFlags := newFlagSet("Execution")
-
- registerExecutionFlags(tschCreateExecFlags.Flags)
- registerExecutionOutputFlags(tschCreateExecFlags.Flags)
-
- cmdFlags[tschCreateCmd] = []*flagSet{
- tschCreateFlags,
- tschCreateExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
-
- tschCreateCmd.Flags().AddFlagSet(tschCreateFlags.Flags)
- tschCreateCmd.Flags().AddFlagSet(tschCreateExecFlags.Flags)
- tschCreateCmd.MarkFlagsOneRequired("exec", "command")
+ tschCreateFlags := newFlagSet("Task Scheduler")
+
+ tschCreateFlags.Flags.StringVarP(&tschTask, "task", "t", "", "Name or path of the new task")
+ tschCreateFlags.Flags.DurationVar(&tschCreate.StopDelay, "delay-stop", 5*time.Second, "Delay between task execution and termination. This won't stop the spawned process")
+ tschCreateFlags.Flags.DurationVar(&tschCreate.StartDelay, "start-delay", 5*time.Second, "Delay between task registration and execution")
+ //tschCreateFlags.Flags.DurationVar(&tschCreate.DeleteDelay, "delete-delay", 0*time.Second, "Delay between task termination and deletion")
+ tschCreateFlags.Flags.BoolVar(&tschCreate.NoDelete, "no-delete", false, "Don't delete task after execution")
+ tschCreateFlags.Flags.BoolVar(&tschCreate.CallDelete, "call-delete", false, "Directly call SchRpcDelete to delete task")
+ tschCreateFlags.Flags.StringVar(&tschCreate.UserSid, "sid", "S-1-5-18", "User `SID` to impersonate")
+
+ tschCreateExecFlags := newFlagSet("Execution")
+
+ registerExecutionFlags(tschCreateExecFlags.Flags)
+ registerExecutionOutputFlags(tschCreateExecFlags.Flags)
+
+ cmdFlags[tschCreateCmd] = []*flagSet{
+ tschCreateFlags,
+ tschCreateExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+
+ tschCreateCmd.Flags().AddFlagSet(tschCreateFlags.Flags)
+ tschCreateCmd.Flags().AddFlagSet(tschCreateExecFlags.Flags)
+ tschCreateCmd.MarkFlagsOneRequired("exec", "command")
}
func tschChangeCmdInit() {
- tschChangeFlags := newFlagSet("Task Scheduler")
-
- tschChangeFlags.Flags.StringVarP(&tschChange.TaskPath, "task", "t", "", "Path to existing task")
- tschChangeFlags.Flags.BoolVar(&tschChange.NoStart, "no-start", false, "Don't start the task")
- tschChangeFlags.Flags.BoolVar(&tschChange.NoRevert, "no-revert", false, "Don't restore the original task definition")
-
- tschChangeExecFlags := newFlagSet("Execution")
-
- registerExecutionFlags(tschChangeExecFlags.Flags)
- registerExecutionOutputFlags(tschChangeExecFlags.Flags)
-
- cmdFlags[tschChangeCmd] = []*flagSet{
- tschChangeFlags,
- tschChangeExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
-
- tschChangeCmd.Flags().AddFlagSet(tschChangeFlags.Flags)
- tschChangeCmd.Flags().AddFlagSet(tschChangeExecFlags.Flags)
-
- // Constraints
- {
- if err := tschChangeCmd.MarkFlagRequired("task"); err != nil {
- panic(err)
- }
- tschChangeCmd.MarkFlagsOneRequired("exec", "command")
- }
+ tschChangeFlags := newFlagSet("Task Scheduler")
+
+ tschChangeFlags.Flags.StringVarP(&tschChange.TaskPath, "task", "t", "", "Path to existing task")
+ tschChangeFlags.Flags.BoolVar(&tschChange.NoStart, "no-start", false, "Don't start the task")
+ tschChangeFlags.Flags.BoolVar(&tschChange.NoRevert, "no-revert", false, "Don't restore the original task definition")
+
+ tschChangeExecFlags := newFlagSet("Execution")
+
+ registerExecutionFlags(tschChangeExecFlags.Flags)
+ registerExecutionOutputFlags(tschChangeExecFlags.Flags)
+
+ cmdFlags[tschChangeCmd] = []*flagSet{
+ tschChangeFlags,
+ tschChangeExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+
+ tschChangeCmd.Flags().AddFlagSet(tschChangeFlags.Flags)
+ tschChangeCmd.Flags().AddFlagSet(tschChangeExecFlags.Flags)
+
+ // Constraints
+ {
+ if err := tschChangeCmd.MarkFlagRequired("task"); err != nil {
+ panic(err)
+ }
+ tschChangeCmd.MarkFlagsOneRequired("exec", "command")
+ }
}
func argsTask(*cobra.Command, []string) error {
- switch {
- case tschTask == "":
- tschTask = `\` + util.RandomString()
- case tschexec.ValidateTaskPath(tschTask) == nil:
- case tschexec.ValidateTaskName(tschTask) == nil:
- tschTask = `\` + tschTask
- default:
- return fmt.Errorf("invalid task Label or path: %q", tschTask)
- }
- return nil
+ switch {
+ case tschTask == "":
+ tschTask = `\` + util.RandomString()
+ case tschexec.ValidateTaskPath(tschTask) == nil:
+ case tschexec.ValidateTaskName(tschTask) == nil:
+ tschTask = `\` + tschTask
+ default:
+ return fmt.Errorf("invalid task Label or path: %q", tschTask)
+ }
+ return nil
}
var (
- tschDemand tschexec.TschDemand
- tschCreate tschexec.TschCreate
- tschChange tschexec.TschChange
-
- tschTask string
-
- tschCmd = &cobra.Command{
- Use: "tsch",
- Short: "Execute with Windows Task Scheduler (MS-TSCH)",
- GroupID: "module",
- Args: cobra.NoArgs,
- }
-
- tschDemandCmd = &cobra.Command{
- Use: "demand [target]",
- Short: "Register a remote scheduled task and demand immediate start",
- Long: `Description:
+ tschDemand tschexec.TschDemand
+ tschCreate tschexec.TschCreate
+ tschChange tschexec.TschChange
+
+ tschTask string
+
+ tschCmd = &cobra.Command{
+ Use: "tsch",
+ Short: "Execute with Windows Task Scheduler (MS-TSCH)",
+ Long: `Description:
+ The tsch module makes use of the Windows Task Scheduler service (MS-TSCH) to
+ spawn processes on the remote target.`,
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
+
+ tschDemandCmd = &cobra.Command{
+ Use: "demand [target]",
+ Short: "Register a remote scheduled task and demand immediate start",
+ Long: `Description:
Similar to the create method, the demand method will call SchRpcRegisterTask,
But rather than setting a defined time when the task will start, it will
- additionally call SchRpcRun to forcefully start the task.
-`,
- Args: args(
- argsRpcClient("cifs"),
- argsOutput("smb"),
- argsTask,
- ),
-
- Run: func(*cobra.Command, []string) {
- tschDemand.IO = exec
- tschDemand.Client = &rpcClient
- tschDemand.TaskPath = tschTask
-
- ctx := log.With().
- Str("module", "tsch").
- Str("method", "demand").
- Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &tschDemand, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
- tschCreateCmd = &cobra.Command{
- Use: "create [target]",
- Short: "Create a remote scheduled task with an automatic start time",
- Long: `Description:
+ additionally call SchRpcRun to forcefully start the task.`,
+ Args: args(
+ argsRpcClient("cifs"),
+ argsOutput("smb"),
+ argsTask,
+ ),
+
+ Run: func(*cobra.Command, []string) {
+ tschDemand.IO = exec
+ tschDemand.Client = &rpcClient
+ tschDemand.TaskPath = tschTask
+
+ ctx := log.With().
+ Str("module", "tsch").
+ Str("method", "demand").
+ Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &tschDemand, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
+ tschCreateCmd = &cobra.Command{
+ Use: "create [target]",
+ Short: "Create a remote scheduled task with an automatic start time",
+ Long: `Description:
The create method calls SchRpcRegisterTask to register a scheduled task
with an automatic start time.This method avoids directly calling SchRpcRun,
and can even avoid calling SchRpcDelete by populating the DeleteExpiredTaskAfter
- Setting.
-`,
- Args: args(
- argsRpcClient("cifs"),
- argsOutput("smb"),
- argsTask,
- ),
-
- Run: func(*cobra.Command, []string) {
- tschCreate.Tsch.Client = &rpcClient
- tschCreate.IO = exec
- tschCreate.TaskPath = tschTask
-
- ctx := log.With().
- Str("module", "tsch").
- Str("method", "create").
- Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &tschCreate, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
- tschChangeCmd = &cobra.Command{
- Use: "change [target]",
- Short: "Modify an existing task to spawn an arbitrary process",
- Long: `Description:
+ Setting.`,
+ Args: args(
+ argsRpcClient("cifs"),
+ argsOutput("smb"),
+ argsTask,
+ ),
+
+ Run: func(*cobra.Command, []string) {
+ tschCreate.Tsch.Client = &rpcClient
+ tschCreate.IO = exec
+ tschCreate.TaskPath = tschTask
+
+ ctx := log.With().
+ Str("module", "tsch").
+ Str("method", "create").
+ Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &tschCreate, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
+ tschChangeCmd = &cobra.Command{
+ Use: "change [target]",
+ Short: "Modify an existing task to spawn an arbitrary process",
+ Long: `Description:
The change method calls SchRpcRetrieveTask to fetch the definition of an existing
task (-t), then modifies the task definition to spawn a process`,
- Args: args(
- argsRpcClient("cifs"),
- argsOutput("smb"),
-
- func(*cobra.Command, []string) error {
- return tschexec.ValidateTaskPath(tschChange.TaskPath)
- },
- ),
-
- Run: func(*cobra.Command, []string) {
- tschChange.Tsch.Client = &rpcClient
- tschChange.IO = exec
-
- ctx := log.With().
- Str("module", "tsch").
- Str("method", "change").
- Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &tschChange, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ Args: args(
+ argsRpcClient("cifs"),
+ argsOutput("smb"),
+
+ func(*cobra.Command, []string) error {
+ return tschexec.ValidateTaskPath(tschChange.TaskPath)
+ },
+ ),
+
+ Run: func(*cobra.Command, []string) {
+ tschChange.Tsch.Client = &rpcClient
+ tschChange.IO = exec
+
+ ctx := log.With().
+ Str("module", "tsch").
+ Str("method", "change").
+ Logger().WithContext(gssapi.NewSecurityContext(context.TODO()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &tschChange, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
)
diff --git a/cmd/wmi.go b/cmd/wmi.go
index b2e463b..90bb5ad 100644
--- a/cmd/wmi.go
+++ b/cmd/wmi.go
@@ -1,143 +1,140 @@
package cmd
import (
- "context"
- "encoding/json"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- wmiexec "github.com/FalconOpsLLC/goexec/pkg/goexec/wmi"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/spf13/cobra"
- "os"
+ "context"
+ "encoding/json"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ wmiexec "github.com/FalconOpsLLC/goexec/pkg/goexec/wmi"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/spf13/cobra"
+ "os"
)
func wmiCmdInit() {
- cmdFlags[wmiCmd] = []*flagSet{
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
- wmiCallCmdInit()
- wmiProcCmdInit()
-
- wmiCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
- wmiCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
- wmiCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
- wmiCmd.AddCommand(wmiProcCmd, wmiCallCmd)
+ cmdFlags[wmiCmd] = []*flagSet{
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+ wmiCallCmdInit()
+ wmiProcCmdInit()
+
+ wmiCmd.PersistentFlags().AddFlagSet(defaultAuthFlags.Flags)
+ wmiCmd.PersistentFlags().AddFlagSet(defaultLogFlags.Flags)
+ wmiCmd.PersistentFlags().AddFlagSet(defaultNetRpcFlags.Flags)
+ wmiCmd.AddCommand(wmiProcCmd, wmiCallCmd)
}
func wmiCallCmdInit() {
- wmiCallFlags := newFlagSet("WMI")
-
- wmiCallFlags.Flags.StringVarP(&wmiCall.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
- wmiCallFlags.Flags.StringVarP(&wmiCall.Class, "class", "C", "", `WMI class to instantiate (i.e. "Win32_Process")`)
- wmiCallFlags.Flags.StringVarP(&wmiCall.Method, "method", "m", "", `WMI Method to call (i.e. "Create")`)
- wmiCallFlags.Flags.StringVarP(&wmiArguments, "args", "A", "{}", `WMI Method argument(s) in JSON dictionary format (i.e. {"Command":"calc.exe"})`)
-
- wmiCallCmd.Flags().AddFlagSet(wmiCallFlags.Flags)
-
- cmdFlags[wmiCallCmd] = []*flagSet{
- wmiCallFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
- if err := wmiCallCmd.MarkFlagRequired("class"); err != nil {
- panic(err)
- }
- if err := wmiCallCmd.MarkFlagRequired("method"); err != nil {
- panic(err)
- }
+ wmiCallFlags := newFlagSet("WMI")
+
+ wmiCallFlags.Flags.StringVarP(&wmiCall.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
+ wmiCallFlags.Flags.StringVarP(&wmiCall.Class, "class", "C", "", `WMI class to instantiate (i.e. "Win32_Process")`)
+ wmiCallFlags.Flags.StringVarP(&wmiCall.Method, "method", "m", "", `WMI Method to call (i.e. "Create")`)
+ wmiCallFlags.Flags.StringVarP(&wmiArguments, "args", "A", "{}", `WMI Method argument(s) in JSON dictionary format (i.e. {"Command":"calc.exe"})`)
+
+ wmiCallCmd.Flags().AddFlagSet(wmiCallFlags.Flags)
+
+ cmdFlags[wmiCallCmd] = []*flagSet{
+ wmiCallFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
+ if err := wmiCallCmd.MarkFlagRequired("class"); err != nil {
+ panic(err)
+ }
+ if err := wmiCallCmd.MarkFlagRequired("method"); err != nil {
+ panic(err)
+ }
}
func wmiProcCmdInit() {
- wmiProcExecFlags := newFlagSet("Execution")
+ wmiProcExecFlags := newFlagSet("Execution")
- registerExecutionFlags(wmiProcExecFlags.Flags)
- registerExecutionOutputFlags(wmiProcExecFlags.Flags)
+ registerExecutionFlags(wmiProcExecFlags.Flags)
+ registerExecutionOutputFlags(wmiProcExecFlags.Flags)
- wmiProcExecFlags.Flags.StringVarP(&wmiProc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
+ wmiProcExecFlags.Flags.StringVarP(&wmiProc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
- cmdFlags[wmiProcCmd] = []*flagSet{
- wmiProcExecFlags,
- defaultAuthFlags,
- defaultLogFlags,
- defaultNetRpcFlags,
- }
+ cmdFlags[wmiProcCmd] = []*flagSet{
+ wmiProcExecFlags,
+ defaultAuthFlags,
+ defaultLogFlags,
+ defaultNetRpcFlags,
+ }
- wmiProcCmd.Flags().AddFlagSet(wmiProcExecFlags.Flags)
+ wmiProcCmd.Flags().AddFlagSet(wmiProcExecFlags.Flags)
}
var (
- wmiCall = wmiexec.WmiCall{}
- wmiProc = wmiexec.WmiProc{}
+ wmiCall = wmiexec.WmiCall{}
+ wmiProc = wmiexec.WmiProc{}
- wmiArguments string
+ wmiArguments string
- wmiCmd = &cobra.Command{
- Use: "wmi",
- Short: "Execute with Windows Management Instrumentation (MS-WMI)",
- Long: `Description:
+ wmiCmd = &cobra.Command{
+ Use: "wmi",
+ Short: "Execute with Windows Management Instrumentation (MS-WMI)",
+ Long: `Description:
The wmi module uses remote Windows Management Instrumentation (WMI) to
- perform various operations including process creation.
-`,
- GroupID: "module",
- Args: cobra.NoArgs,
- }
-
- wmiCallCmd = &cobra.Command{
- Use: "call [target]",
- Short: "Execute specified WMI method",
- Long: `Description:
+ perform various operations including process creation.`,
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
+
+ wmiCallCmd = &cobra.Command{
+ Use: "call [target]",
+ Short: "Execute specified WMI method",
+ Long: `Description:
The call method creates an instance of the specified WMI class (-c),
- then calls the provided method (-m) with the provided arguments (-A).
-`,
- Args: args(
- argsRpcClient("cifs"),
- func(cmd *cobra.Command, args []string) error {
- return json.Unmarshal([]byte(wmiArguments), &wmiCall.Args)
- }),
-
- Run: func(cmd *cobra.Command, args []string) {
- wmiCall.Client = &rpcClient
- wmiCall.Out = os.Stdout
-
- ctx := log.With().
- Str("module", "wmi").
- Str("method", "call").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanAuxiliaryMethod(ctx, &wmiCall); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
-
- wmiProcCmd = &cobra.Command{
- Use: "proc [target]",
- Short: "Start a Windows process",
- Long: `Description:
+ then calls the provided method (-m) with the provided arguments (-A).`,
+ Args: args(
+ argsRpcClient("cifs"),
+ func(cmd *cobra.Command, args []string) error {
+ return json.Unmarshal([]byte(wmiArguments), &wmiCall.Args)
+ }),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ wmiCall.Client = &rpcClient
+ wmiCall.Out = os.Stdout
+
+ ctx := log.With().
+ Str("module", "wmi").
+ Str("method", "call").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanAuxiliaryMethod(ctx, &wmiCall); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
+
+ wmiProcCmd = &cobra.Command{
+ Use: "proc [target]",
+ Short: "Start a Windows process",
+ Long: `Description:
The proc method creates an instance of the Win32_Process WMI class, then
calls the Win32_Process.Create method with the provided command (-c),
- and optional working directory (-d).
-`,
- Args: args(
- argsRpcClient("cifs"),
- argsOutput("smb"),
- ),
-
- Run: func(cmd *cobra.Command, args []string) {
- wmiProc.Client = &rpcClient
- wmiProc.IO = exec
- wmiProc.Resource = "//./root/cimv2"
-
- ctx := log.With().
- Str("module", "wmi").
- Str("method", "proc").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &wmiProc, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ and optional working directory (-d).`,
+ Args: args(
+ argsRpcClient("cifs"),
+ argsOutput("smb"),
+ ),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ wmiProc.Client = &rpcClient
+ wmiProc.IO = exec
+ wmiProc.Resource = "//./root/cimv2"
+
+ ctx := log.With().
+ Str("module", "wmi").
+ Str("method", "proc").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &wmiProc, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
)