diff options
author | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-25 10:44:52 -0500 |
---|---|---|
committer | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-25 10:44:52 -0500 |
commit | 865b523bdd4b006661ef8fbf76d24e4b7ad1cf8e (patch) | |
tree | c71109362f375cfecdacc96fcb90da982109de0a | |
parent | c523a600769c4f043cbc52e0493ab47c0144062f (diff) | |
download | goexec-865b523bdd4b006661ef8fbf76d24e4b7ad1cf8e.tar.gz goexec-865b523bdd4b006661ef8fbf76d24e4b7ad1cf8e.zip |
Small cosmetic changes in Cobra cmdsv0.1.1
-rw-r--r-- | cmd/dcom.go | 113 | ||||
-rw-r--r-- | cmd/root.go | 376 | ||||
-rw-r--r-- | cmd/scmr.go | 391 | ||||
-rw-r--r-- | cmd/tsch.go | 397 | ||||
-rw-r--r-- | cmd/wmi.go | 231 |
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") + } + }, + } ) @@ -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") + } + }, + } ) |