diff options
author | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-03-09 12:26:05 -0500 |
---|---|---|
committer | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-03-09 12:26:05 -0500 |
commit | c6460b19bd834875b00f199390e6121d5bdfba7e (patch) | |
tree | 11cf6c9c3ddbdf694547cea50c2375d2b6d0df7c /cmd | |
parent | 8099a1d45007ba86f353647bf2a3f09d0cfc73a7 (diff) | |
download | goexec-c6460b19bd834875b00f199390e6121d5bdfba7e.tar.gz goexec-c6460b19bd834875b00f199390e6121d5bdfba7e.zip |
massively improved SCMR module + new DCE client
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/root.go | 36 | ||||
-rw-r--r-- | cmd/rpc.go | 85 | ||||
-rw-r--r-- | cmd/scmr.go | 106 | ||||
-rw-r--r-- | cmd/tsch.go | 366 |
4 files changed, 313 insertions, 280 deletions
diff --git a/cmd/root.go b/cmd/root.go index 441cafc..f083063 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -23,24 +23,6 @@ var ( executableArgs string workingDirectory string - needsTarget = func(proto string) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) (err error) { - if len(args) != 1 { - return fmt.Errorf("command require exactly one positional argument: [target]") - } - if creds, target, err = authOpts.WithTarget(ctx, proto, args[0]); err != nil { - return fmt.Errorf("failed to parse target: %w", err) - } - if creds == nil { - return fmt.Errorf("no credentials supplied") - } - if target == nil { - return fmt.Errorf("no target supplied") - } - return - } - } - rootCmd = &cobra.Command{ Use: "goexec", PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { @@ -57,6 +39,24 @@ var ( } ) +func needsTarget(proto string) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) (err error) { + if len(args) != 1 { + return fmt.Errorf("command require exactly one positional argument: [target]") + } + if creds, target, err = authOpts.WithTarget(ctx, proto, args[0]); err != nil { + return fmt.Errorf("failed to parse target: %w", err) + } + if creds == nil { + return fmt.Errorf("no credentials supplied") + } + if target == nil { + return fmt.Errorf("no target supplied") + } + return + } +} + func init() { ctx = context.Background() @@ -2,61 +2,66 @@ package cmd import ( "fmt" + "github.com/FalconOpsLLC/goexec/internal/client/dce" "github.com/oiweiwei/go-msrpc/dcerpc" "github.com/spf13/cobra" "regexp" ) -var ( - // DCE options - argDceStringBinding string - argDceEpmFilter string - argDceEpmAuto bool - argDceNoEpm bool - argDceNoSeal bool - argDceNoSign bool - dceStringBinding *dcerpc.StringBinding - dceOptions []dcerpc.Option - - needsRpcTarget = func(proto string) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) (err error) { - if argDceStringBinding != "" { - dceStringBinding, err = dcerpc.ParseStringBinding(argDceStringBinding) - if err != nil { - return fmt.Errorf("failed to parse RPC endpoint: %w", err) - } - argDceNoEpm = true // If an explicit endpoint is set, don't use EPM - - } else if argDceEpmFilter != "" { - // This ensures that filters like "ncacn_ip_tcp" will be made into a valid binding (i.e. "ncacn_ip_tcp:") - if ok, err := regexp.MatchString(`^\w+$`, argDceEpmFilter); err == nil && ok { - argDceEpmFilter += ":" - } - dceStringBinding, err = dcerpc.ParseStringBinding(argDceEpmFilter) - if err != nil { - return fmt.Errorf("failed to parse EPM filter: %w", err) - } +func needsRpcTarget(proto string) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) (err error) { + + if argDceStringBinding != "" { + dceConfig.Endpoint, err = dcerpc.ParseStringBinding(argDceStringBinding) + if err != nil { + return fmt.Errorf("failed to parse RPC endpoint: %w", err) } - if !argDceNoSign { - dceOptions = append(dceOptions, dcerpc.WithSign()) + dceConfig.NoEpm = true // If an explicit endpoint is set, don't use EPM + + } else if argDceEpmFilter != "" { + // This ensures that filters like "ncacn_ip_tcp" will be made into a valid binding (i.e. "ncacn_ip_tcp:") + if ok, err := regexp.MatchString(`^\w+$`, argDceEpmFilter); err == nil && ok { + argDceEpmFilter += ":" } - if argDceNoSeal { - dceOptions = append(dceOptions, dcerpc.WithInsecure()) - } else { - dceOptions = append(dceOptions, dcerpc.WithSeal()) + dceConfig.Endpoint, err = dcerpc.ParseStringBinding(argDceEpmFilter) + if err != nil { + return fmt.Errorf("failed to parse EPM filter: %w", err) } - return needsTarget(proto)(cmd, args) } + if !argDceNoSign { + dceConfig.DceOptions = append(dceConfig.DceOptions, dcerpc.WithSign()) + dceConfig.EpmOptions = append(dceConfig.EpmOptions, dcerpc.WithSign()) + } + if argDceNoSeal { + dceConfig.DceOptions = append(dceConfig.DceOptions, dcerpc.WithInsecure()) + } else { + dceConfig.DceOptions = append(dceConfig.DceOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) + dceConfig.EpmOptions = append(dceConfig.EpmOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) + } + return needsTarget(proto)(cmd, args) } +} + +var ( + // DCE arguments + argDceStringBinding string + argDceEpmFilter string + argDceNoSeal bool + argDceNoSign bool + + // DCE options + dceStringBinding *dcerpc.StringBinding + dceConfig dce.ConnectionMethodDCEConfig ) func registerRpcFlags(cmd *cobra.Command) { - cmd.PersistentFlags().StringVarP(&argDceEpmFilter, "epm-filter", "F", "", "String binding to filter endpoints returned by EPM") - cmd.PersistentFlags().StringVar(&argDceStringBinding, "endpoint", "", "Explicit RPC endpoint definition") - cmd.PersistentFlags().BoolVar(&argDceNoEpm, "no-epm", false, "Do not use EPM to automatically detect endpoints") + cmd.PersistentFlags().BoolVar(&dceConfig.NoEpm, "no-epm", false, "Do not use EPM to automatically detect endpoints") + cmd.PersistentFlags().BoolVar(&dceConfig.EpmAuto, "epm-auto", false, "Automatically detect endpoints instead of using the module defaults") cmd.PersistentFlags().BoolVar(&argDceNoSign, "no-sign", false, "Disable signing on DCE messages") cmd.PersistentFlags().BoolVar(&argDceNoSeal, "no-seal", false, "Disable packet stub encryption on DCE messages") - cmd.PersistentFlags().BoolVar(&argDceEpmAuto, "epm-auto", false, "Automatically detect endpoints instead of using the module defaults") + cmd.PersistentFlags().StringVarP(&argDceEpmFilter, "epm-filter", "F", "", "String binding to filter endpoints returned by EPM") + cmd.PersistentFlags().StringVar(&argDceStringBinding, "endpoint", "", "Explicit RPC endpoint definition") + cmd.MarkFlagsMutuallyExclusive("endpoint", "epm-filter") cmd.MarkFlagsMutuallyExclusive("no-epm", "epm-filter") } diff --git a/cmd/scmr.go b/cmd/scmr.go index f2f0d51..7772fc4 100644 --- a/cmd/scmr.go +++ b/cmd/scmr.go @@ -1,8 +1,8 @@ package cmd import ( - "fmt" "github.com/FalconOpsLLC/goexec/internal/exec" + "github.com/FalconOpsLLC/goexec/internal/util" "github.com/FalconOpsLLC/goexec/internal/windows" "github.com/RedTeamPentesting/adauth" "github.com/spf13/cobra" @@ -14,11 +14,11 @@ func scmrCmdInit() { registerRpcFlags(scmrCmd) scmrCmd.PersistentFlags().StringVarP(&executablePath, "executable-path", "f", "", "Full path to remote Windows executable") scmrCmd.PersistentFlags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable") - scmrCmd.PersistentFlags().StringVarP(&scmrName, "service-name", "s", "", "Name of service to create or modify") - - scmrCmd.MarkPersistentFlagRequired("executable-path") - scmrCmd.MarkPersistentFlagRequired("service-name") + scmrCmd.PersistentFlags().StringVarP(&scmrServiceName, "service-name", "s", "", "Name of service to create or modify") + if err := scmrCmd.MarkPersistentFlagRequired("executable-path"); err != nil { + panic(err) + } scmrCmd.AddCommand(scmrChangeCmd) scmrCreateCmdInit() scmrCmd.AddCommand(scmrCreateCmd) @@ -28,30 +28,24 @@ func scmrCmdInit() { func scmrChangeCmdInit() { scmrChangeCmd.Flags().StringVarP(&scmrDisplayName, "display-name", "n", "", "Display name of service to create") scmrChangeCmd.Flags().BoolVar(&scmrNoStart, "no-start", false, "Don't start service") + scmrChangeCmd.Flags().StringVarP(&scmrServiceName, "service-name", "s", "", "Name of service to modify") + if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil { + panic(err) + } } func scmrCreateCmdInit() { + scmrCreateCmd.Flags().StringVarP(&scmrServiceName, "service-name", "s", "", "Name of service to create") scmrCreateCmd.Flags().BoolVar(&scmrNoDelete, "no-delete", false, "Don't delete service after execution") } var ( // scmr arguments - scmrName string + scmrServiceName string scmrDisplayName string scmrNoDelete bool scmrNoStart bool - scmrArgs = func(cmd *cobra.Command, args []string) (err error) { - if len(args) != 1 { - return fmt.Errorf("expected exactly 1 positional argument, got %d", len(args)) - } - if creds, target, err = authOpts.WithTarget(ctx, "cifs", args[0]); err != nil { - return fmt.Errorf("failed to parse target: %w", err) - } - log.Debug().Str("target", args[0]).Msg("Resolved target") - return nil - } - creds *adauth.Credential target *adauth.Target @@ -63,16 +57,29 @@ var ( scmrCreateCmd = &cobra.Command{ Use: "create [target]", Short: "Create & run a new Windows service to gain execution", - Args: scmrArgs, - RunE: func(cmd *cobra.Command, args []string) (err error) { + Args: needsRpcTarget("cifs"), + Run: func(cmd *cobra.Command, args []string) { + + if scmrServiceName == "" { + log.Warn().Msg("No service name was specified, using random string") + scmrServiceName = util.RandomString() + } if scmrNoDelete { log.Warn().Msg("Service will not be deleted after execution") } if scmrDisplayName == "" { - scmrDisplayName = scmrName - log.Warn().Msg("No display name specified, using service name as display name") + log.Debug().Msg("No display name specified, using service name as display name") + scmrDisplayName = scmrServiceName } + executor := scmrexec.Module{} + cleanCfg := &exec.CleanupConfig{ + CleanupMethod: scmrexec.CleanupMethodDelete, + } + connCfg := &exec.ConnectionConfig{ + ConnectionMethod: exec.ConnectionMethodDCE, + ConnectionMethodConfig: dceConfig, + } execCfg := &exec.ExecutionConfig{ ExecutablePath: executablePath, ExecutableArgs: executableArgs, @@ -80,36 +87,73 @@ var ( ExecutionMethodConfig: scmrexec.MethodCreateConfig{ NoDelete: scmrNoDelete, - ServiceName: scmrName, + ServiceName: util.RandomStringIfBlank(scmrServiceName), DisplayName: scmrDisplayName, ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, StartType: windows.SERVICE_DEMAND_START, }, } - if err := executor.Exec(log.WithContext(ctx), creds, target, execCfg); err != nil { - log.Fatal().Err(err).Msg("SCMR execution failed") + ctx = log.With(). + Str("module", "scmr"). + Str("method", "create"). + Logger().WithContext(ctx) + + if err := executor.Connect(ctx, creds, target, connCfg); err != nil { + log.Fatal().Err(err).Msg("Connection failed") + } + if !scmrNoDelete { + defer func() { + if err := executor.Cleanup(ctx, cleanCfg); err != nil { + log.Error().Err(err).Msg("Cleanup failed") + } + }() + } + if err := executor.Exec(ctx, execCfg); err != nil { + log.Error().Err(err).Msg("Execution failed") } - return nil }, } scmrChangeCmd = &cobra.Command{ Use: "change [target]", Short: "Change an existing Windows service to gain execution", - Args: scmrArgs, + Args: needsRpcTarget("cifs"), Run: func(cmd *cobra.Command, args []string) { + executor := scmrexec.Module{} + cleanCfg := &exec.CleanupConfig{ + CleanupMethod: scmrexec.CleanupMethodRevert, + } + connCfg := &exec.ConnectionConfig{ + ConnectionMethod: exec.ConnectionMethodDCE, + ConnectionMethodConfig: dceConfig, + } execCfg := &exec.ExecutionConfig{ ExecutablePath: executablePath, ExecutableArgs: executableArgs, - ExecutionMethod: scmrexec.MethodModify, + ExecutionMethod: scmrexec.MethodChange, - ExecutionMethodConfig: scmrexec.MethodModifyConfig{ + ExecutionMethodConfig: scmrexec.MethodChangeConfig{ NoStart: scmrNoStart, - ServiceName: scmrName, + ServiceName: scmrServiceName, }, } - if err := executor.Exec(log.WithContext(ctx), creds, target, execCfg); err != nil { - log.Fatal().Err(err).Msg("SCMR execution failed") + log = log.With(). + Str("module", "scmr"). + Str("method", "change"). + Logger() + + if err := executor.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { + log.Fatal().Err(err).Msg("Connection failed") + } + if !scmrNoDelete { + defer func() { + if err := executor.Cleanup(log.WithContext(ctx), cleanCfg); err != nil { + log.Error().Err(err).Msg("Cleanup failed") + } + }() + } + if err := executor.Exec(log.WithContext(ctx), execCfg); err != nil { + log.Error().Err(err).Msg("Execution failed") } }, } diff --git a/cmd/tsch.go b/cmd/tsch.go index 31c2dce..c7ab3a3 100644 --- a/cmd/tsch.go +++ b/cmd/tsch.go @@ -1,100 +1,99 @@ package cmd import ( - "fmt" - "github.com/FalconOpsLLC/goexec/internal/client/dce" - "github.com/FalconOpsLLC/goexec/internal/exec" - "github.com/FalconOpsLLC/goexec/internal/exec/tsch" - "github.com/spf13/cobra" - "regexp" - "time" + "fmt" + "github.com/FalconOpsLLC/goexec/internal/exec" + "github.com/FalconOpsLLC/goexec/internal/exec/tsch" + "github.com/spf13/cobra" + "regexp" + "time" ) func tschCmdInit() { - registerRpcFlags(tschCmd) - - tschDeleteCmdInit() - tschCmd.AddCommand(tschDeleteCmd) - tschRegisterCmdInit() - tschCmd.AddCommand(tschRegisterCmd) - tschDemandCmdInit() - tschCmd.AddCommand(tschDemandCmd) + registerRpcFlags(tschCmd) + + tschDeleteCmdInit() + tschCmd.AddCommand(tschDeleteCmd) + tschRegisterCmdInit() + tschCmd.AddCommand(tschRegisterCmd) + tschDemandCmdInit() + tschCmd.AddCommand(tschDemandCmd) } func tschDeleteCmdInit() { - tschDeleteCmd.Flags().StringVarP(&tschTaskPath, "path", "t", "", "Scheduled task path") - if err := tschDeleteCmd.MarkFlagRequired("path"); err != nil { - panic(err) - } + tschDeleteCmd.Flags().StringVarP(&tschTaskPath, "path", "t", "", "Scheduled task path") + if err := tschDeleteCmd.MarkFlagRequired("path"); err != nil { + panic(err) + } } func tschDemandCmdInit() { - tschDemandCmd.Flags().StringVarP(&executable, "executable", "e", "", "Remote Windows executable to invoke") - tschDemandCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable") - tschDemandCmd.Flags().StringVarP(&tschTaskName, "name", "n", "", "Target task name") - tschDemandCmd.Flags().BoolVar(&tschNoDelete, "no-delete", false, "Don't delete task after execution") - if err := tschDemandCmd.MarkFlagRequired("executable"); err != nil { - panic(err) - } + tschDemandCmd.Flags().StringVarP(&executable, "executable", "e", "", "Remote Windows executable to invoke") + tschDemandCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable") + tschDemandCmd.Flags().StringVarP(&tschTaskName, "name", "n", "", "Target task name") + tschDemandCmd.Flags().BoolVar(&tschNoDelete, "no-delete", false, "Don't delete task after execution") + if err := tschDemandCmd.MarkFlagRequired("executable"); err != nil { + panic(err) + } } func tschRegisterCmdInit() { - tschRegisterCmd.Flags().StringVarP(&executable, "executable", "e", "", "Remote Windows executable to invoke") - tschRegisterCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable") - tschRegisterCmd.Flags().StringVarP(&tschTaskName, "name", "n", "", "Target task name") - tschRegisterCmd.Flags().DurationVar(&tschStopDelay, "delay-stop", time.Duration(5*time.Second), "Delay between task execution and termination. This will not stop the process spawned by the task") - tschRegisterCmd.Flags().DurationVarP(&tschDelay, "delay-start", "d", time.Duration(5*time.Second), "Delay between task registration and execution") - tschRegisterCmd.Flags().DurationVarP(&tschDeleteDelay, "delay-delete", "D", time.Duration(0*time.Second), "Delay between task termination and deletion") - tschRegisterCmd.Flags().BoolVar(&tschNoDelete, "no-delete", false, "Don't delete task after execution") - tschRegisterCmd.Flags().BoolVar(&tschCallDelete, "call-delete", false, "Directly call SchRpcDelete to delete task") - - tschRegisterCmd.MarkFlagsMutuallyExclusive("no-delete", "delay-delete") - tschRegisterCmd.MarkFlagsMutuallyExclusive("no-delete", "call-delete") - tschRegisterCmd.MarkFlagsMutuallyExclusive("delay-delete", "call-delete") - - if err := tschRegisterCmd.MarkFlagRequired("executable"); err != nil { - panic(err) - } + tschRegisterCmd.Flags().StringVarP(&executable, "executable", "e", "", "Remote Windows executable to invoke") + tschRegisterCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable") + tschRegisterCmd.Flags().StringVarP(&tschTaskName, "name", "n", "", "Target task name") + tschRegisterCmd.Flags().DurationVar(&tschStopDelay, "delay-stop", time.Duration(5*time.Second), "Delay between task execution and termination. This will not stop the process spawned by the task") + tschRegisterCmd.Flags().DurationVarP(&tschDelay, "delay-start", "d", time.Duration(5*time.Second), "Delay between task registration and execution") + tschRegisterCmd.Flags().DurationVarP(&tschDeleteDelay, "delay-delete", "D", time.Duration(0*time.Second), "Delay between task termination and deletion") + tschRegisterCmd.Flags().BoolVar(&tschNoDelete, "no-delete", false, "Don't delete task after execution") + tschRegisterCmd.Flags().BoolVar(&tschCallDelete, "call-delete", false, "Directly call SchRpcDelete to delete task") + + tschRegisterCmd.MarkFlagsMutuallyExclusive("no-delete", "delay-delete") + tschRegisterCmd.MarkFlagsMutuallyExclusive("no-delete", "call-delete") + tschRegisterCmd.MarkFlagsMutuallyExclusive("delay-delete", "call-delete") + + if err := tschRegisterCmd.MarkFlagRequired("executable"); err != nil { + panic(err) + } } func tschArgs(principal string) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { - if tschTaskPath != "" && !tschTaskPathRegex.MatchString(tschTaskPath) { - return fmt.Errorf("invalid task path: %s", tschTaskPath) - } - if tschTaskName != "" { - if !tschTaskNameRegex.MatchString(tschTaskName) { - return fmt.Errorf("invalid task name: %s", tschTaskName) - - } else if tschTaskPath == "" { - tschTaskPath = `\` + tschTaskName - } - } - return needsRpcTarget(principal)(cmd, args) - } + return func(cmd *cobra.Command, args []string) error { + if tschTaskPath != "" && !tschTaskPathRegex.MatchString(tschTaskPath) { + return fmt.Errorf("invalid task path: %s", tschTaskPath) + } + if tschTaskName != "" { + if !tschTaskNameRegex.MatchString(tschTaskName) { + return fmt.Errorf("invalid task name: %s", tschTaskName) + + } else if tschTaskPath == "" { + tschTaskPath = `\` + tschTaskName + } + } + return needsRpcTarget(principal)(cmd, args) + } } var ( - tschNoDelete bool - tschCallDelete bool - tschDeleteDelay time.Duration - tschStopDelay time.Duration - tschDelay time.Duration - tschTaskName string - tschTaskPath string - - tschTaskPathRegex = regexp.MustCompile(`^\\[^ :/\\][^:/]*$`) - tschTaskNameRegex = regexp.MustCompile(`^[^ :/\\][^:/\\]*$`) - - tschCmd = &cobra.Command{ - Use: "tsch", - Short: "Establish execution via TSCH (ITaskSchedulerService)", - Args: cobra.NoArgs, - } - tschRegisterCmd = &cobra.Command{ - Use: "register [target]", - Short: "Register a remote scheduled task with an automatic start time", - Long: `Description: + tschNoDelete bool + tschCallDelete bool + tschDeleteDelay time.Duration + tschStopDelay time.Duration + tschDelay time.Duration + tschTaskName string + tschTaskPath string + + tschTaskPathRegex = regexp.MustCompile(`^\\[^ :/\\][^:/]*$`) + tschTaskNameRegex = regexp.MustCompile(`^[^ :/\\][^:/\\]*$`) + + tschCmd = &cobra.Command{ + Use: "tsch", + Short: "Establish execution via TSCH (ITaskSchedulerService)", + Args: cobra.NoArgs, + } + tschRegisterCmd = &cobra.Command{ + Use: "register [target]", + Short: "Register a remote scheduled task with an automatic start time", + Long: `Description: The register 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 @@ -106,52 +105,47 @@ References: SchRpcDelete - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/360bb9b1-dd2a-4b36-83ee-21f12cb97cff DeleteExpiredTaskAfter - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/6bfde6fe-440e-4ddd-b4d6-c8fc0bc06fae `, - Args: tschArgs("cifs"), - Run: func(cmd *cobra.Command, args []string) { - - log = log.With(). - Str("module", "tsch"). - Str("method", "register"). - Logger() - if tschNoDelete { - log.Warn().Msg("Task will not be deleted after execution") - } - - module := tschexec.Module{} - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dce.ConnectionMethodDCEConfig{ - Endpoint: dceStringBinding, - Options: dceOptions, - EpmAuto: argDceEpmAuto, - NoEpm: argDceNoEpm, - }, - } - execCfg := &exec.ExecutionConfig{ - ExecutableName: executable, - ExecutableArgs: executableArgs, - ExecutionMethod: tschexec.MethodRegister, - - ExecutionMethodConfig: tschexec.MethodRegisterConfig{ - NoDelete: tschNoDelete, - CallDelete: tschCallDelete, - StartDelay: tschDelay, - StopDelay: tschStopDelay, - DeleteDelay: tschDeleteDelay, - TaskPath: tschTaskPath, - }, - } - if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { - log.Fatal().Err(err).Msg("Connection failed") - } else if err = module.Exec(log.WithContext(ctx), execCfg); err != nil { - log.Fatal().Err(err).Msg("Execution failed") - } - }, - } - tschDemandCmd = &cobra.Command{ - Use: "demand [target]", - Short: "Register a remote scheduled task and demand immediate start", - Long: `Description: + Args: tschArgs("cifs"), + Run: func(cmd *cobra.Command, args []string) { + + log = log.With(). + Str("module", "tsch"). + Str("method", "register"). + Logger() + if tschNoDelete { + log.Warn().Msg("Task will not be deleted after execution") + } + + module := tschexec.Module{} + connCfg := &exec.ConnectionConfig{ + ConnectionMethod: exec.ConnectionMethodDCE, + ConnectionMethodConfig: dceConfig, + } + execCfg := &exec.ExecutionConfig{ + ExecutableName: executable, + ExecutableArgs: executableArgs, + ExecutionMethod: tschexec.MethodRegister, + + ExecutionMethodConfig: tschexec.MethodRegisterConfig{ + NoDelete: tschNoDelete, + CallDelete: tschCallDelete, + StartDelay: tschDelay, + StopDelay: tschStopDelay, + DeleteDelay: tschDeleteDelay, + TaskPath: tschTaskPath, + }, + } + if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { + log.Fatal().Err(err).Msg("Connection failed") + } else if err = module.Exec(log.WithContext(ctx), execCfg); err != nil { + log.Fatal().Err(err).Msg("Execution failed") + } + }, + } + tschDemandCmd = &cobra.Command{ + Use: "demand [target]", + Short: "Register a remote scheduled task and demand immediate start", + Long: `Description: Similar to the register 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. @@ -160,78 +154,68 @@ References: SchRpcRegisterTask - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/849c131a-64e4-46ef-b015-9d4c599c5167 SchRpcRun - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/77f2250d-500a-40ee-be18-c82f7079c4f0 `, - Args: tschArgs("cifs"), - Run: func(cmd *cobra.Command, args []string) { - - log = log.With(). - Str("module", "tsch"). - Str("method", "register"). - Logger() - if tschNoDelete { - log.Warn().Msg("Task will not be deleted after execution") - } - module := tschexec.Module{} - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dce.ConnectionMethodDCEConfig{ - Endpoint: dceStringBinding, - Options: dceOptions, - EpmAuto: argDceEpmAuto, - NoEpm: argDceNoEpm, - }, - } - execCfg := &exec.ExecutionConfig{ - ExecutableName: executable, - ExecutableArgs: executableArgs, - ExecutionMethod: tschexec.MethodDemand, - - ExecutionMethodConfig: tschexec.MethodDemandConfig{ - NoDelete: tschNoDelete, - TaskPath: tschTaskPath, - }, - } - if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { - log.Fatal().Err(err).Msg("Connection failed") - } else if err = module.Exec(log.WithContext(ctx), execCfg); err != nil { - log.Fatal().Err(err).Msg("Execution failed") - } - }, - } - tschDeleteCmd = &cobra.Command{ - Use: "delete [target]", - Short: "Manually delete a scheduled task", - Long: `Description: + Args: tschArgs("cifs"), + Run: func(cmd *cobra.Command, args []string) { + + log = log.With(). + Str("module", "tsch"). + Str("method", "register"). + Logger() + if tschNoDelete { + log.Warn().Msg("Task will not be deleted after execution") + } + module := tschexec.Module{} + connCfg := &exec.ConnectionConfig{ + ConnectionMethod: exec.ConnectionMethodDCE, + ConnectionMethodConfig: dceConfig, + } + execCfg := &exec.ExecutionConfig{ + ExecutableName: executable, + ExecutableArgs: executableArgs, + ExecutionMethod: tschexec.MethodDemand, + + ExecutionMethodConfig: tschexec.MethodDemandConfig{ + NoDelete: tschNoDelete, + TaskPath: tschTaskPath, + }, + } + if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { + log.Fatal().Err(err).Msg("Connection failed") + } else if err = module.Exec(log.WithContext(ctx), execCfg); err != nil { + log.Fatal().Err(err).Msg("Execution failed") + } + }, + } + tschDeleteCmd = &cobra.Command{ + Use: "delete [target]", + Short: "Manually delete a scheduled task", + Long: `Description: The delete method manually deletes a scheduled task by calling SchRpcDelete References: SchRpcDelete - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/360bb9b1-dd2a-4b36-83ee-21f12cb97cff `, - Args: tschArgs("cifs"), - Run: func(cmd *cobra.Command, args []string) { - log = log.With(). - Str("module", "tsch"). - Str("method", "delete"). - Logger() - - module := tschexec.Module{} - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dce.ConnectionMethodDCEConfig{ - Endpoint: dceStringBinding, - Options: dceOptions, - EpmAuto: argDceEpmAuto, - NoEpm: argDceNoEpm, - }, - } - cleanCfg := &exec.CleanupConfig{ - CleanupMethod: tschexec.MethodDelete, - CleanupMethodConfig: tschexec.MethodDeleteConfig{TaskPath: tschTaskPath}, - } - if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { - log.Fatal().Err(err).Msg("Connection failed") - } else if err := module.Cleanup(log.WithContext(ctx), cleanCfg); err != nil { - log.Fatal().Err(err).Msg("Cleanup failed") - } - }, - } + Args: tschArgs("cifs"), + Run: func(cmd *cobra.Command, args []string) { + log = log.With(). + Str("module", "tsch"). + Str("method", "delete"). + Logger() + + module := tschexec.Module{} + connCfg := &exec.ConnectionConfig{ + ConnectionMethod: exec.ConnectionMethodDCE, + ConnectionMethodConfig: dceConfig, + } + cleanCfg := &exec.CleanupConfig{ + CleanupMethod: tschexec.MethodDelete, + CleanupMethodConfig: tschexec.MethodDeleteConfig{TaskPath: tschTaskPath}, + } + if err := module.Connect(log.WithContext(ctx), creds, target, connCfg); err != nil { + log.Fatal().Err(err).Msg("Connection failed") + } else if err := module.Cleanup(log.WithContext(ctx), cleanCfg); err != nil { + log.Fatal().Err(err).Msg("Cleanup failed") + } + }, + } ) |