aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md2
-rw-r--r--cmd/scmr.go46
-rw-r--r--internal/exec/scmr/exec.go17
-rw-r--r--internal/exec/scmr/module.go6
4 files changed, 46 insertions, 25 deletions
diff --git a/TODO.md b/TODO.md
index 4b2c54f..610751f 100644
--- a/TODO.md
+++ b/TODO.md
@@ -18,10 +18,12 @@
- [ ] Add psexec module (RemComSvc)
- [ ] Add support for dynamic service executable (of course)
+
### Other
- [ ] Fix SCMR `change` method so that dependencies field isn't permanently overwritten
- [ ] Add `delete` command to all modules that may involve cleanup - use `tsch delete` for reference
+ - [X] `scmr delete`
- [ ] Standardize modules to interface for future use
- [ ] Add command to tsch - update task if it already exists. See https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/849c131a-64e4-46ef-b015-9d4c599c5167 (`flags` argument)
- [ ] Add proxy support - see https://github.com/oiweiwei/go-msrpc/issues/21
diff --git a/cmd/scmr.go b/cmd/scmr.go
index 37b52eb..9df9ef1 100644
--- a/cmd/scmr.go
+++ b/cmd/scmr.go
@@ -5,6 +5,7 @@ import (
"github.com/FalconOpsLLC/goexec/internal/util"
"github.com/FalconOpsLLC/goexec/internal/windows"
"github.com/RedTeamPentesting/adauth"
+ "github.com/oiweiwei/go-msrpc/dcerpc"
"github.com/spf13/cobra"
scmrexec "github.com/FalconOpsLLC/goexec/internal/exec/scmr"
@@ -12,48 +13,51 @@ import (
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(&scmrServiceName, "service-name", "s", "", "Name of service to create or modify")
-
- if err := scmrCmd.MarkPersistentFlagRequired("executable-path"); err != nil {
- panic(err)
- }
scmrCreateCmdInit()
- scmrCmd.AddCommand(scmrChangeCmd)
- scmrChangeCmdInit()
scmrCmd.AddCommand(scmrCreateCmd)
+ scmrChangeCmdInit()
+ scmrCmd.AddCommand(scmrChangeCmd)
scmrDeleteCmdInit()
scmrCmd.AddCommand(scmrDeleteCmd)
}
func scmrCreateCmdInit() {
+ scmrCreateCmd.Flags().StringVarP(&scmrDisplayName, "display-name", "n", "", "Display name of service to create")
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")
+ scmrCreateCmd.Flags().BoolVar(&scmrNoStart, "no-start", false, "Don't start service")
+ scmrCreateCmd.Flags().StringVarP(&executablePath, "executable-path", "f", "", "Full path to a remote Windows executable file")
+ scmrCreateCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to the executable")
+ if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil {
+ panic(err)
+ }
}
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")
+ scmrChangeCmd.Flags().StringVarP(&executablePath, "executable-path", "f", "", "Full path to remote Windows executable")
+ scmrChangeCmd.Flags().StringVarP(&executableArgs, "args", "a", "", "Arguments to pass to executable")
if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil {
panic(err)
}
}
func scmrDeleteCmdInit() {
- scmrDeleteCmd.Flags().StringVarP(&scmrServiceName, "service-name", "s", "", "Name of service to delete")
- if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil {
+ scmrDeleteCmd.Flags().StringArrayVarP(&scmrServiceNames, "service-name", "s", scmrServiceNames, "Name of service(s) to delete")
+ if err := scmrDeleteCmd.MarkFlagRequired("service-name"); err != nil {
panic(err)
}
}
var (
// scmr arguments
- scmrServiceName string
- scmrDisplayName string
- scmrNoDelete bool
- scmrNoStart bool
+ scmrServiceName string
+ scmrServiceNames []string
+ scmrDisplayName string
+ scmrNoDelete bool
+ scmrNoStart bool
creds *adauth.Credential
target *adauth.Target
@@ -90,7 +94,8 @@ References:
executor := scmrexec.Module{}
cleanCfg := &exec.CleanupConfig{
- CleanupMethod: scmrexec.CleanupMethodDelete,
+ CleanupMethod: scmrexec.CleanupMethodDelete,
+ CleanupMethodConfig: scmrexec.CleanupMethodDeleteConfig{},
}
connCfg := &exec.ConnectionConfig{
ConnectionMethod: exec.ConnectionMethodDCE,
@@ -137,7 +142,8 @@ References:
executor := scmrexec.Module{}
cleanCfg := &exec.CleanupConfig{
- CleanupMethod: scmrexec.CleanupMethodRevert,
+ CleanupMethod: scmrexec.CleanupMethodRevert,
+ CleanupMethodConfig: scmrexec.CleanupMethodRevertConfig{},
}
connCfg := &exec.ConnectionConfig{
ConnectionMethod: exec.ConnectionMethodDCE,
@@ -177,14 +183,16 @@ References:
Use: "delete [target]",
Short: "Delete an existing Windows service",
Long: `Description:
-
+TODO
`,
Args: needsRpcTarget("cifs"),
Run: func(cmd *cobra.Command, args []string) {
+ dceConfig.DceOptions = append(dceConfig.DceOptions, dcerpc.WithInsecure())
executor := scmrexec.Module{}
cleanCfg := &exec.CleanupConfig{
- CleanupMethod: scmrexec.CleanupMethodDelete,
+ CleanupMethod: scmrexec.CleanupMethodDelete,
+ CleanupMethodConfig: scmrexec.CleanupMethodDeleteConfig{ServiceNames: scmrServiceNames},
}
connCfg := &exec.ConnectionConfig{
ConnectionMethod: exec.ConnectionMethodDCE,
diff --git a/internal/exec/scmr/exec.go b/internal/exec/scmr/exec.go
index 588c580..7134df0 100644
--- a/internal/exec/scmr/exec.go
+++ b/internal/exec/scmr/exec.go
@@ -70,9 +70,14 @@ func (mod *Module) Cleanup(ctx context.Context, ccfg *exec.CleanupConfig) (err e
Str("func", "Cleanup").Logger()
if len(mod.services) == 0 {
- return nil
+ if cfg, ok := ccfg.CleanupMethodConfig.(CleanupMethodDeleteConfig); ok && len(cfg.ServiceNames) > 0 {
+ for _, svcName := range cfg.ServiceNames {
+ if svcName != "" {
+ mod.services = append(mod.services, remoteService{name: svcName})
+ }
+ }
+ }
}
-
if mod.dce == nil || mod.ctl == nil {
// Try to reconnect
if err := mod.reconnect(ctx); err != nil {
@@ -88,11 +93,11 @@ func (mod *Module) Cleanup(ctx context.Context, ccfg *exec.CleanupConfig) (err e
DatabaseName: "ServicesActive\x00",
DesiredAccess: ServiceAllAccess, // TODO: Replace
}); err != nil {
- log.Error().Err(err).Msg("Failed to reopen an SCM handle")
+ log.Error().Err(err).Msg("Failed to open an SCM handle")
return err
} else {
mod.scm = resp.SCM
- log.Info().Msg("Reopened SCM handle")
+ log.Info().Msg("Opened an SCM handle")
}
}
@@ -106,12 +111,12 @@ func (mod *Module) Cleanup(ctx context.Context, ccfg *exec.CleanupConfig) (err e
ServiceName: rsvc.name,
DesiredAccess: windows.SERVICE_DELETE | windows.SERVICE_CHANGE_CONFIG,
}); err != nil {
- log.Error().Err(err).Msg("Failed to reopen a service handle")
+ log.Error().Err(err).Msg("Failed to open a service handle")
continue
} else {
rsvc.handle = or.Service
}
- log.Info().Msg("Service handle reopened")
+ log.Info().Msg("Service handle opened")
}
if ccfg.CleanupMethod == CleanupMethodDelete {
// Delete the service
diff --git a/internal/exec/scmr/module.go b/internal/exec/scmr/module.go
index 2a2d378..0372668 100644
--- a/internal/exec/scmr/module.go
+++ b/internal/exec/scmr/module.go
@@ -36,3 +36,9 @@ type MethodChangeConfig struct {
NoStart bool
ServiceName string
}
+
+type CleanupMethodDeleteConfig struct {
+ ServiceNames []string
+}
+
+type CleanupMethodRevertConfig struct{}