aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorBryan McNulty <bryanmcnulty@protonmail.com>2025-03-09 12:26:05 -0500
committerBryan McNulty <bryanmcnulty@protonmail.com>2025-03-09 12:26:05 -0500
commitc6460b19bd834875b00f199390e6121d5bdfba7e (patch)
tree11cf6c9c3ddbdf694547cea50c2375d2b6d0df7c /cmd
parent8099a1d45007ba86f353647bf2a3f09d0cfc73a7 (diff)
downloadgoexec-c6460b19bd834875b00f199390e6121d5bdfba7e.tar.gz
goexec-c6460b19bd834875b00f199390e6121d5bdfba7e.zip
massively improved SCMR module + new DCE client
Diffstat (limited to 'cmd')
-rw-r--r--cmd/root.go36
-rw-r--r--cmd/rpc.go85
-rw-r--r--cmd/scmr.go106
-rw-r--r--cmd/tsch.go366
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()
diff --git a/cmd/rpc.go b/cmd/rpc.go
index 9a92a89..7290b06 100644
--- a/cmd/rpc.go
+++ b/cmd/rpc.go
@@ -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")
+ }
+ },
+ }
)