From 55eb4275fb760ac7a3ce1444f5ae0ded9e2ff91c Mon Sep 17 00:00:00 2001 From: Bryan McNulty Date: Wed, 16 Apr 2025 12:11:58 -0500 Subject: rewrote everything lol --- cmd/scmr.go | 243 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 125 insertions(+), 118 deletions(-) (limited to 'cmd/scmr.go') diff --git a/cmd/scmr.go b/cmd/scmr.go index 11e1379..08e23d7 100644 --- a/cmd/scmr.go +++ b/cmd/scmr.go @@ -1,14 +1,12 @@ package cmd import ( - "github.com/FalconOpsLLC/goexec/internal/exec" + "context" "github.com/FalconOpsLLC/goexec/internal/util" - "github.com/FalconOpsLLC/goexec/internal/windows" - "github.com/RedTeamPentesting/adauth" - "github.com/oiweiwei/go-msrpc/dcerpc" + "github.com/oiweiwei/go-msrpc/ssp/gssapi" "github.com/spf13/cobra" - scmrexec "github.com/FalconOpsLLC/goexec/internal/exec/scmr" + scmrexec "github.com/FalconOpsLLC/goexec/pkg/goexec/scmr" ) func scmrCmdInit() { @@ -22,53 +20,55 @@ func scmrCmdInit() { } 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") - scmrCreateCmd.Flags().BoolVarP(&scmrOutput, "output", "O", false, "Fetch program output") + scmrCreateCmd.Flags().StringVarP(&scmrCreate.DisplayName, "display-name", "n", "", "Display name of service to create") + scmrCreateCmd.Flags().StringVarP(&scmrCreate.ServiceName, "service-name", "s", "", "Name of service to create") + scmrCreateCmd.Flags().BoolVar(&scmrCreate.NoDelete, "no-delete", false, "Don't delete service after execution") + scmrCreateCmd.Flags().BoolVar(&scmrCreate.NoStart, "no-start", false, "Don't start service") + + scmrCreateCmd.Flags().StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to a remote Windows executable") + scmrCreateCmd.Flags().StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to the executable") + + scmrCreateCmd.MarkFlagsMutuallyExclusive("no-delete", "no-start") + 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") + scmrChangeCmd.Flags().BoolVar(&scmrChange.NoStart, "no-start", false, "Don't start service") + scmrChangeCmd.Flags().StringVarP(&scmrChange.ServiceName, "service-name", "s", "", "Name of service to modify") + + scmrChangeCmd.Flags().StringVarP(&exec.Input.ExecutablePath, "executable-path", "f", "", "Full path to remote Windows executable") + scmrChangeCmd.Flags().StringVarP(&exec.Input.Arguments, "args", "a", "", "Arguments to pass to executable") + if err := scmrChangeCmd.MarkFlagRequired("service-name"); err != nil { panic(err) } + if err := scmrCreateCmd.MarkFlagRequired("executable-path"); err != nil { + panic(err) + } } func scmrDeleteCmdInit() { - scmrDeleteCmd.Flags().StringArrayVarP(&scmrServiceNames, "service-name", "s", scmrServiceNames, "Name of service(s) to delete") + scmrDeleteCmd.Flags().StringVarP(&scmrDelete.ServiceName, "service-name", "s", scmrDelete.ServiceName, "Name of service to delete") + if err := scmrDeleteCmd.MarkFlagRequired("service-name"); err != nil { panic(err) } } var ( - // scmr arguments - scmrServiceName string - scmrServiceNames []string - scmrDisplayName string - scmrNoDelete bool - scmrNoStart bool - scmrOutput bool - - creds *adauth.Credential - target *adauth.Target + scmrCreate scmrexec.ScmrCreate + scmrChange scmrexec.ScmrChange + scmrDelete scmrexec.ScmrDelete scmrCmd = &cobra.Command{ Use: "scmr", Short: "Establish execution via SCMR", Args: cobra.NoArgs, } + scmrCreateCmd = &cobra.Command{ Use: "create [target]", Short: "Create & run a new Windows service to gain execution", @@ -79,138 +79,145 @@ var ( References: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e `, - Args: needs(needsTarget("host"), needsRpcTarget("host")), + Args: argsRpcClient("cifs"), + Run: func(cmd *cobra.Command, args []string) { + var err error + + ctx := gssapi.NewSecurityContext(context.Background()) - if scmrServiceName == "" { - log.Warn().Msg("No service name was specified, using random string") - scmrServiceName = util.RandomString() + ctx = log.With(). + Str("module", "scmr"). + Str("method", "create"). + Logger(). + WithContext(ctx) + + if scmrCreate.ServiceName == "" { + log.Warn().Msg("No service name was provided. Using a random string") + scmrCreate.ServiceName = util.RandomString() } - if scmrNoDelete { + + if scmrCreate.NoDelete { log.Warn().Msg("Service will not be deleted after execution") } - if scmrDisplayName == "" { + + if scmrCreate.DisplayName == "" { log.Debug().Msg("No display name specified, using service name as display name") - scmrDisplayName = scmrServiceName + scmrCreate.DisplayName = scmrCreate.ServiceName } - executor := scmrexec.Module{} - cleanCfg := &exec.CleanupConfig{ - CleanupMethod: scmrexec.CleanupMethodDelete, - CleanupMethodConfig: scmrexec.CleanupMethodDeleteConfig{}, - } - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dceConfig, - } - execCfg := &exec.ExecutionConfig{ - ExecutablePath: executablePath, - ExecutableArgs: executableArgs, - ReturnOutput: scmrOutput, - ExecutionMethod: scmrexec.MethodCreate, - - ExecutionMethodConfig: scmrexec.MethodCreateConfig{ - NoDelete: scmrNoDelete, - ServiceName: util.RandomStringIfBlank(scmrServiceName), - DisplayName: scmrDisplayName, - ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, - StartType: windows.SERVICE_DEMAND_START, - }, - } - ctx = log.With(). - Str("module", "scmr"). - Str("method", "create"). - Logger().WithContext(ctx) - - if err := executor.Connect(ctx, creds, target, connCfg); err != nil { + if err = rpcClient.Connect(ctx); 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") - } - }() + + defer func() { + closeErr := rpcClient.Close(ctx) + if closeErr != nil { + log.Error().Err(closeErr).Msg("Failed to close connection") + } + }() + + defer func() { + cleanErr := scmrCreate.Clean(ctx) + if cleanErr != nil { + log.Warn().Err(cleanErr).Msg("Clean operation failed") + } + }() + + if err = scmrCreate.Init(ctx, &rpcClient); err != nil { + log.Error().Err(err).Msg("Module initialization failed") + returnCode = 2 + return } - if err := executor.Exec(ctx, execCfg); err != nil { + + if err = scmrCreate.Execute(ctx, exec.Input); err != nil { log.Error().Err(err).Msg("Execution failed") + returnCode = 4 } }, } + scmrChangeCmd = &cobra.Command{ Use: "change [target]", Short: "Change an existing Windows service to gain execution", - Args: needs(needsTarget("host"), needsRpcTarget("host")), + Args: argsRpcClient("cifs"), Run: func(cmd *cobra.Command, args []string) { + var err error + + ctx := gssapi.NewSecurityContext(context.Background()) - executor := scmrexec.Module{} - cleanCfg := &exec.CleanupConfig{ - CleanupMethod: scmrexec.CleanupMethodRevert, - CleanupMethodConfig: scmrexec.CleanupMethodRevertConfig{}, - } - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dceConfig, - } - execCfg := &exec.ExecutionConfig{ - ExecutablePath: executablePath, - ExecutableArgs: executableArgs, - ExecutionMethod: scmrexec.MethodChange, - - ExecutionMethodConfig: scmrexec.MethodChangeConfig{ - NoStart: scmrNoStart, - ServiceName: scmrServiceName, - }, - } ctx = log.With(). Str("module", "scmr"). Str("method", "change"). - Logger().WithContext(ctx) + Logger(). + WithContext(ctx) - if err := executor.Connect(ctx, creds, target, connCfg); err != nil { + if err = rpcClient.Connect(ctx); 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") - } - }() + + defer func() { + closeErr := rpcClient.Close(ctx) + if closeErr != nil { + log.Error().Err(closeErr).Msg("Failed to close connection") + } + }() + + defer func() { + cleanErr := scmrChange.Clean(ctx) + if cleanErr != nil { + log.Warn().Err(cleanErr).Msg("Clean operation failed") + } + }() + + if err = scmrChange.Init(ctx, &rpcClient); err != nil { + log.Error().Err(err).Msg("Module initialization failed") + returnCode = 2 + return } - if err := executor.Exec(ctx, execCfg); err != nil { + + if err = scmrChange.Execute(ctx, exec.Input); err != nil { log.Error().Err(err).Msg("Execution failed") + returnCode = 4 } }, } scmrDeleteCmd = &cobra.Command{ Use: "delete [target]", Short: "Delete an existing Windows service", - Long: `Description: -TODO -`, - Args: needs(needsTarget("host"), needsRpcTarget("host")), + Long: `TODO`, + + Args: argsRpcClient("cifs"), Run: func(cmd *cobra.Command, args []string) { - dceConfig.DceOptions = append(dceConfig.DceOptions, dcerpc.WithInsecure()) + var err error + + ctx := gssapi.NewSecurityContext(context.Background()) - executor := scmrexec.Module{} - cleanCfg := &exec.CleanupConfig{ - CleanupMethod: scmrexec.CleanupMethodDelete, - CleanupMethodConfig: scmrexec.CleanupMethodDeleteConfig{ServiceNames: scmrServiceNames}, - } - connCfg := &exec.ConnectionConfig{ - ConnectionMethod: exec.ConnectionMethodDCE, - ConnectionMethodConfig: dceConfig, - } ctx = log.With(). Str("module", "scmr"). Str("method", "delete"). - Logger().WithContext(ctx) + Logger(). + WithContext(ctx) - if err := executor.Connect(ctx, creds, target, connCfg); err != nil { + if err = rpcClient.Connect(ctx); err != nil { log.Fatal().Err(err).Msg("Connection failed") + } + + defer func() { + closeErr := rpcClient.Close(ctx) + if closeErr != nil { + log.Error().Err(closeErr).Msg("Failed to close connection") + } + }() + + if err = scmrDelete.Init(ctx, &rpcClient); err != nil { + log.Error().Err(err).Msg("Module initialization failed") + returnCode = 2 + } - } else if err = executor.Cleanup(ctx, cleanCfg); err != nil { - log.Fatal().Err(err).Msg("Delete failed") + if err = scmrDelete.Clean(ctx); err != nil { + log.Warn().Err(err).Msg("Clean failed") + returnCode = 4 } }, } -- cgit v1.2.3