aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan McNulty <bryan@falconops.com>2025-04-26 15:27:23 -0500
committerGitHub <noreply@github.com>2025-04-26 15:27:23 -0500
commit27d183952ad83c871264b558d9bde405da553ec9 (patch)
treee9e80bc0daab7e636d3cb084ceb07c22cbc56467
parentbac8bd6865a4dc6ad6cbd791a0141d4e5d988007 (diff)
parentaadf3819a559db8186ba92078dfc33d0f92e47ed (diff)
downloadgoexec-27d183952ad83c871264b558d9bde405da553ec9.tar.gz
goexec-27d183952ad83c871264b558d9bde405da553ec9.zip
Merge pull request #9 from FalconOpsLLC/dev
WMI module bug fixed, update actions, add remote error refs
-rw-r--r--.github/workflows/go.yml13
-rw-r--r--cmd/args.go3
-rw-r--r--cmd/dcom.go110
-rw-r--r--cmd/root.go506
-rw-r--r--cmd/tsch.go386
-rw-r--r--pkg/goexec/dce/client.go3
-rw-r--r--pkg/goexec/dcom/dcom.go44
-rw-r--r--pkg/goexec/dcom/module.go247
-rw-r--r--pkg/goexec/dcom/util.go125
-rw-r--r--pkg/goexec/scmr/create.go219
-rw-r--r--pkg/goexec/scmr/module.go3
-rw-r--r--pkg/goexec/scmr/scmr.go8
-rw-r--r--pkg/goexec/tsch/change.go219
-rw-r--r--pkg/goexec/tsch/demand.go133
-rw-r--r--pkg/goexec/tsch/module.go255
-rw-r--r--pkg/goexec/tsch/task/action.go2
-rw-r--r--pkg/goexec/tsch/tsch.go3
-rw-r--r--pkg/goexec/wmi/module.go15
18 files changed, 1167 insertions, 1127 deletions
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 58cbddb..d66ea98 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -1,5 +1,6 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
+# Adapted from https://github.com/RedTeamPentesting/adauth/blob/main/.github/workflows/check.yml :)
name: Go
@@ -20,6 +21,18 @@ jobs:
with:
go-version: ${{ matrix.go-version }}
+ - name: Lint
+ uses: golangci/golangci-lint-action@v3
+ with:
+ version: v1.64
+ args: --verbose --timeout 5m
+
+ - name: Check go.mod
+ run: |
+ echo "check if go.mod is up to date"
+ go mod tidy
+ git diff --exit-code go.mod
+
- name: Build
run: go build -v ./...
diff --git a/cmd/args.go b/cmd/args.go
index 9568395..40b9701 100644
--- a/cmd/args.go
+++ b/cmd/args.go
@@ -29,10 +29,13 @@ func registerNetworkFlags(fs *pflag.FlagSet) {
//cmd.MarkFlagsMutuallyExclusive("no-epm", "epm-filter")
}
+// FUTURE: automatically stage & execute file
+/*
func registerStageFlags(fs *pflag.FlagSet) {
fs.StringVarP(&stageFilePath, "stage", "E", "", "File to stage and execute")
//fs.StringVarP(&stageArgs ...)
}
+*/
func registerExecutionFlags(fs *pflag.FlagSet) {
fs.StringVarP(&exec.Input.Executable, "exec", "e", "", "Remote Windows executable to invoke")
diff --git a/cmd/dcom.go b/cmd/dcom.go
index 89fac18..1a8d031 100644
--- a/cmd/dcom.go
+++ b/cmd/dcom.go
@@ -1,80 +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)",
- Long: `Description:
+ 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,
- }
+ 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
+ Args: args(
+ argsRpcClient("host"),
+ argsOutput("smb"),
+ ),
+ Run: func(cmd *cobra.Command, args []string) {
+ dcomMmc.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 96173a4..a66fa62 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,26 +1,26 @@
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"
- "runtime/pprof"
+ "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"
+ "runtime/pprof"
)
type flagSet struct {
- Label string
- Flags *pflag.FlagSet
+ Label string
+ Flags *pflag.FlagSet
}
const helpTemplate = `Usage:{{if .Runnable}}
@@ -52,55 +52,55 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
`
var (
- cmdFlags = make(map[*cobra.Command][]*flagSet)
-
- defaultAuthFlags, defaultLogFlags, defaultNetRpcFlags *flagSet
-
- returnCode int
- toClose []io.Closer
-
- // === 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
- // ===============
-
- // === Resource profiling ===
- cpuProfile string
- memProfile string
- cpuProfileFile io.WriteCloser
- memProfileFile io.WriteCloser
- // ==========================
-
- 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
+ toClose []io.Closer
+
+ // === IO ===
+ //stageFilePath string // FUTURE
+ 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.InfoLevel
+ logFile io.WriteCloser = os.Stderr
+ log zerolog.Logger
+ // ===============
+
+ // === Network ===
+ proxy string
+ rpcClient dce.Client
+ smbClient smb.Client
+ // ===============
+
+ // === Resource profiling ===
+ cpuProfile string
+ memProfile string
+ cpuProfileFile io.WriteCloser
+ memProfileFile io.WriteCloser
+ // ==========================
+
+ 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: `
___ ___ ___ _ _ ___ ___
| . | . | -_|_'_| -_| _|
|_ |___|___|_,_|___|___|
@@ -113,200 +113,200 @@ 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
- }
- toClose = append(toClose, logFile)
- 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)
- }
-
- // CPU / memory profiling
- {
- if cpuProfile != "" {
- if cpuProfileFile, err = os.OpenFile(cpuProfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
- log.Error().Err(err).Msg("Failed to open CPU profile for writing")
- return
- }
- toClose = append(toClose, cpuProfileFile)
-
- if err = pprof.StartCPUProfile(cpuProfileFile); err != nil {
- log.Error().Err(err).Msg("Failed to start CPU profile")
- return
- }
- }
- if memProfile != "" {
- if memProfileFile, err = os.OpenFile(memProfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
- log.Error().Err(err).Msg("Failed to open memory profile for writing")
- return
- }
- toClose = append(toClose, memProfileFile)
- }
- }
-
- 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 memProfileFile != nil {
- if err := pprof.WriteHeapProfile(memProfileFile); err != nil {
- log.Error().Err(err).Msg("Failed to write memory profile")
- return
- }
- }
-
- if cpuProfileFile != nil {
- pprof.StopCPUProfile()
- }
-
- for _, c := range toClose {
- if c != nil {
- if err := c.Close(); err != nil {
- log.Warn().Err(err).Msg("Failed to close stream")
- }
- }
- }
-
- if exec.Input != nil && exec.Input.StageFile != 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
+ }
+ toClose = append(toClose, logFile)
+ 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)
+ }
+
+ // CPU / memory profiling
+ {
+ if cpuProfile != "" {
+ if cpuProfileFile, err = os.OpenFile(cpuProfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
+ log.Error().Err(err).Msg("Failed to open CPU profile for writing")
+ return
+ }
+ toClose = append(toClose, cpuProfileFile)
+
+ if err = pprof.StartCPUProfile(cpuProfileFile); err != nil {
+ log.Error().Err(err).Msg("Failed to start CPU profile")
+ return
+ }
+ }
+ if memProfile != "" {
+ if memProfileFile, err = os.OpenFile(memProfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
+ log.Error().Err(err).Msg("Failed to open memory profile for writing")
+ return
+ }
+ toClose = append(toClose, memProfileFile)
+ }
+ }
+
+ 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 memProfileFile != nil {
+ if err := pprof.WriteHeapProfile(memProfileFile); err != nil {
+ log.Error().Err(err).Msg("Failed to write memory profile")
+ return
+ }
+ }
+
+ if cpuProfileFile != nil {
+ pprof.StopCPUProfile()
+ }
+
+ if exec.Input != nil && exec.Input.StageFile != nil {
+ if err := exec.Input.StageFile.Close(); err != nil {
+ log.Warn().Err(err).Msg("Failed to close stage file")
+ }
+ }
+
+ for _, c := range toClose {
+ if c != nil {
+ if err := c.Close(); err != nil {
+ log.Warn().Err(err).Msg("Failed to close stream")
+ }
+ }
+ }
+ },
+ }
)
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)
- }
-
- // CPU / Memory profiling
- {
- rootCmd.PersistentFlags().StringVar(&cpuProfile, "cpu-profile", "", "Write CPU profile to `file`")
- rootCmd.PersistentFlags().StringVar(&memProfile, "mem-profile", "", "Write memory profile to `file`")
-
- if err := rootCmd.PersistentFlags().MarkHidden("cpu-profile"); err != nil {
- panic(err)
- }
- if err := rootCmd.PersistentFlags().MarkHidden("mem-profile"); err != nil {
- panic(err)
- }
- }
-
- // 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)
- }
- }
+ // Auth init
+ {
+ gssapi.AddMechanism(ssp.SPNEGO)
+ gssapi.AddMechanism(ssp.NTLM)
+ gssapi.AddMechanism(ssp.KRB5)
+ }
+
+ // CPU / Memory profiling
+ {
+ rootCmd.PersistentFlags().StringVar(&cpuProfile, "cpu-profile", "", "Write CPU profile to `file`")
+ rootCmd.PersistentFlags().StringVar(&memProfile, "mem-profile", "", "Write memory profile to `file`")
+
+ if err := rootCmd.PersistentFlags().MarkHidden("cpu-profile"); err != nil {
+ panic(err)
+ }
+ if err := rootCmd.PersistentFlags().MarkHidden("mem-profile"); err != nil {
+ panic(err)
+ }
+ }
+
+ // 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/tsch.go b/cmd/tsch.go
index ec3504f..f58caf6 100644
--- a/cmd/tsch.go
+++ b/cmd/tsch.go
@@ -1,233 +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
+ tschDemand tschexec.TschDemand
+ tschCreate tschexec.TschCreate
+ tschChange tschexec.TschChange
- tschTask string
+ tschTask string
- tschCmd = &cobra.Command{
- Use: "tsch",
- Short: "Execute with Windows Task Scheduler (MS-TSCH)",
- Long: `Description:
+ 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:
+ 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:
+ 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:
+ Args: args(
+ argsRpcClient("cifs"),
+ argsOutput("smb"),
+ argsTask,
+ ),
+
+ Run: func(*cobra.Command, []string) {
+ tschCreate.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.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")
+ }
+ },
+ }
)
diff --git a/pkg/goexec/dce/client.go b/pkg/goexec/dce/client.go
index 0918933..567d619 100644
--- a/pkg/goexec/dce/client.go
+++ b/pkg/goexec/dce/client.go
@@ -13,8 +13,7 @@ import (
type Client struct {
Options
- conn dcerpc.Conn
- hostname string
+ conn dcerpc.Conn
}
func (c *Client) String() string {
diff --git a/pkg/goexec/dcom/dcom.go b/pkg/goexec/dcom/dcom.go
index 41f48d6..a504e1a 100644
--- a/pkg/goexec/dcom/dcom.go
+++ b/pkg/goexec/dcom/dcom.go
@@ -1,33 +1,33 @@
package dcomexec
import (
- googleUUID "github.com/google/uuid"
- "github.com/oiweiwei/go-msrpc/midl/uuid"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom"
- "github.com/oiweiwei/go-msrpc/msrpc/dtyp"
+ googleUUID "github.com/google/uuid"
+ "github.com/oiweiwei/go-msrpc/midl/uuid"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom"
+ "github.com/oiweiwei/go-msrpc/msrpc/dtyp"
)
const (
- LcEnglishUs uint32 = 0x409
+ LcEnglishUs uint32 = 0x409
)
var (
- ShellWindowsUuid = uuid.MustParse("9BA05972-F6A8-11CF-A442-00A0C90A8F39")
- Mmc20Uuid = uuid.MustParse("49B2791A-B1AE-4C90-9B8E-E860BA07F889")
+ //ShellWindowsUuid = uuid.MustParse("9BA05972-F6A8-11CF-A442-00A0C90A8F39")
+ //Mmc20Uuid = uuid.MustParse("49B2791A-B1AE-4C90-9B8E-E860BA07F889")
- RandCid = dcom.CID(*dtyp.GUIDFromUUID(uuid.MustParse(googleUUID.NewString())))
- IDispatchIID = &dcom.IID{
- Data1: 0x20400,
- Data2: 0x0,
- Data3: 0x0,
- Data4: []byte{0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46},
- }
- ComVersion = &dcom.COMVersion{
- MajorVersion: 5,
- MinorVersion: 7,
- }
- ORPCThis = &dcom.ORPCThis{
- Version: ComVersion,
- CID: &RandCid,
- }
+ RandCid = dcom.CID(*dtyp.GUIDFromUUID(uuid.MustParse(googleUUID.NewString())))
+ IDispatchIID = &dcom.IID{
+ Data1: 0x20400,
+ Data2: 0x0,
+ Data3: 0x0,
+ Data4: []byte{0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46},
+ }
+ ComVersion = &dcom.COMVersion{
+ MajorVersion: 5,
+ MinorVersion: 7,
+ }
+ ORPCThis = &dcom.ORPCThis{
+ Version: ComVersion,
+ CID: &RandCid,
+ }
)
diff --git a/pkg/goexec/dcom/module.go b/pkg/goexec/dcom/module.go
index 1aa44c1..b6fc4d4 100644
--- a/pkg/goexec/dcom/module.go
+++ b/pkg/goexec/dcom/module.go
@@ -1,142 +1,145 @@
package dcomexec
import (
- "context"
- "errors"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
- "github.com/oiweiwei/go-msrpc/dcerpc"
- "github.com/oiweiwei/go-msrpc/midl/uuid"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/iremotescmactivator/v0"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut/idispatch/v0"
- "github.com/oiweiwei/go-msrpc/msrpc/dtyp"
- "github.com/rs/zerolog"
+ "context"
+ "errors"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
+ "github.com/oiweiwei/go-msrpc/dcerpc"
+ "github.com/oiweiwei/go-msrpc/midl/uuid"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom/iremotescmactivator/v0"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut/idispatch/v0"
+ "github.com/oiweiwei/go-msrpc/msrpc/dtyp"
+ "github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
- ModuleName = "DCOM"
+ ModuleName = "DCOM"
)
type Dcom struct {
- goexec.Cleaner
- goexec.Executor
+ goexec.Cleaner
+ goexec.Executor
- Client *dce.Client
- ClassID string
+ Client *dce.Client
+ ClassID string
- dispatchClient idispatch.DispatchClient
+ dispatchClient idispatch.DispatchClient
}
func (m *Dcom) Connect(ctx context.Context) (err error) {
- if err = m.Client.Connect(ctx); err == nil {
- m.AddCleaners(m.Client.Close)
- }
- return
+ if err = m.Client.Connect(ctx); err == nil {
+ m.AddCleaners(m.Client.Close)
+ }
+ return
}
func (m *Dcom) Init(ctx context.Context) (err error) {
- log := zerolog.Ctx(ctx).With().
- Str("module", ModuleName).Logger()
-
- if m.Client == nil || m.Client.Dce() == nil {
- return errors.New("DCE connection not initialized")
- }
-
- m.ClassID = "49B2791A-B1AE-4C90-9B8E-E860BA07F889"
- //m.ClassID = "9BA05972-F6A8-11CF-A442-00A0C90A8F39"
- class := dcom.ClassID(*dtyp.GUIDFromUUID(uuid.MustParse(m.ClassID)))
-
- if class.GUID() == nil {
- return fmt.Errorf("invalid class ID: %s", m.ClassID)
- }
-
- opts := []dcerpc.Option{
- dcerpc.WithSign(),
- }
-
- inst := &dcom.InstantiationInfoData{
- ClassID: &class,
- IID: []*dcom.IID{IDispatchIID},
- ClientCOMVersion: ComVersion,
- }
- ac := &dcom.ActivationContextInfoData{}
- loc := &dcom.LocationInfoData{}
- scm := &dcom.SCMRequestInfoData{
- RemoteRequest: &dcom.CustomRemoteRequestSCMInfo{
- RequestedProtocolSequences: []uint16{7},
- },
- }
-
- ap := &dcom.ActivationProperties{
- DestinationContext: 2,
- Properties: []dcom.ActivationProperty{inst, ac, loc, scm},
- }
-
- apin, err := ap.ActivationPropertiesIn()
- if err != nil {
- return err
- }
-
- act, err := iremotescmactivator.NewRemoteSCMActivatorClient(ctx, m.Client.Dce())
- if err != nil {
- return err
- }
-
- cr, err := act.RemoteCreateInstance(ctx, &iremotescmactivator.RemoteCreateInstanceRequest{
- ORPCThis: &dcom.ORPCThis{
- Version: ComVersion,
- Flags: 1,
- CID: &RandCid,
- },
- ActPropertiesIn: apin,
- })
- if err != nil {
- return err
- }
- log.Info().Msg("RemoteCreateInstance succeeded")
-
- apout := new(dcom.ActivationProperties)
- if err = apout.Parse(cr.ActPropertiesOut); err != nil {
- return err
- }
- si := apout.SCMReplyInfoData()
- pi := apout.PropertiesOutInfo()
-
- if si == nil {
- return fmt.Errorf("remote create instance response: SCMReplyInfoData is nil")
- }
-
- if pi == nil {
- return fmt.Errorf("remote create instance response: PropertiesOutInfo is nil")
- }
-
- // Ensure that the string bindings don't contain the target hostname
- for _, bind := range si.RemoteReply.OXIDBindings.GetStringBindings() {
- stringBinding, err := dcerpc.ParseStringBinding("ncacn_ip_tcp:" + bind.NetworkAddr) // TODO: try bind.String()
-
- if err != nil {
- log.Debug().Err(err).Msg("Failed to parse string binding")
- continue
- }
- stringBinding.NetworkAddress = ""
- opts = append(opts, dcerpc.WithEndpoint(stringBinding.String()))
- }
-
- err = m.Client.Reconnect(ctx, opts...)
- if err != nil {
- return err
- }
- log.Info().Msg("created new DCERPC dialer")
-
- m.dispatchClient, err = idispatch.NewDispatchClient(ctx, m.Client.Dce(), dcom.WithIPID(pi.InterfaceData[0].IPID()))
- if err != nil {
- return err
- }
- log.Info().Msg("created IDispatch Client")
-
- return
+ log := zerolog.Ctx(ctx).With().
+ Str("module", ModuleName).Logger()
+
+ if m.Client == nil || m.Client.Dce() == nil {
+ return errors.New("DCE connection not initialized")
+ }
+
+ m.ClassID = "49B2791A-B1AE-4C90-9B8E-E860BA07F889"
+ //m.ClassID = "9BA05972-F6A8-11CF-A442-00A0C90A8F39"
+ class := dcom.ClassID(*dtyp.GUIDFromUUID(uuid.MustParse(m.ClassID)))
+
+ if class.GUID() == nil {
+ return fmt.Errorf("invalid class ID: %s", m.ClassID)
+ }
+
+ opts := []dcerpc.Option{
+ dcerpc.WithSign(),
+ }
+
+ inst := &dcom.InstantiationInfoData{
+ ClassID: &class,
+ IID: []*dcom.IID{IDispatchIID},
+ ClientCOMVersion: ComVersion,
+ }
+ ac := &dcom.ActivationContextInfoData{}
+ loc := &dcom.LocationInfoData{}
+ scm := &dcom.SCMRequestInfoData{
+ RemoteRequest: &dcom.CustomRemoteRequestSCMInfo{
+ RequestedProtocolSequences: []uint16{7},
+ },
+ }
+
+ ap := &dcom.ActivationProperties{
+ DestinationContext: 2,
+ Properties: []dcom.ActivationProperty{inst, ac, loc, scm},
+ }
+
+ apin, err := ap.ActivationPropertiesIn()
+ if err != nil {
+ return err
+ }
+
+ act, err := iremotescmactivator.NewRemoteSCMActivatorClient(ctx, m.Client.Dce())
+ if err != nil {
+ return err
+ }
+
+ cr, err := act.RemoteCreateInstance(ctx, &iremotescmactivator.RemoteCreateInstanceRequest{
+ ORPCThis: &dcom.ORPCThis{
+ Version: ComVersion,
+ Flags: 1,
+ CID: &RandCid,
+ },
+ ActPropertiesIn: apin,
+ })
+ if err != nil {
+ return err
+ }
+ log.Info().Msg("RemoteCreateInstance succeeded")
+
+ apout := new(dcom.ActivationProperties)
+ if err = apout.Parse(cr.ActPropertiesOut); err != nil {
+ return err
+ }
+ si := apout.SCMReplyInfoData()
+ pi := apout.PropertiesOutInfo()
+
+ if si == nil {
+ return fmt.Errorf("remote create instance response: SCMReplyInfoData is nil")
+ }
+
+ if pi == nil {
+ return fmt.Errorf("remote create instance response: PropertiesOutInfo is nil")
+ }
+
+ // Ensure that the string bindings don't contain the target hostname
+ for _, bind := range si.RemoteReply.OXIDBindings.GetStringBindings() {
+ stringBinding, err := dcerpc.ParseStringBinding("ncacn_ip_tcp:" + bind.NetworkAddr) // TODO: try bind.String()
+
+ if err != nil {
+ log.Debug().Err(err).Msg("Failed to parse string binding")
+ continue
+ }
+ stringBinding.NetworkAddress = ""
+ opts = append(opts, dcerpc.WithEndpoint(stringBinding.String()))
+ }
+
+ err = m.Client.Reconnect(ctx, opts...)
+ if err != nil {
+ return err
+ }
+ log.Info().Msg("created new DCERPC dialer")
+
+ m.dispatchClient, err = idispatch.NewDispatchClient(ctx, m.Client.Dce(), dcom.WithIPID(pi.InterfaceData[0].IPID()))
+ if err != nil {
+ return err
+ }
+ log.Info().Msg("created IDispatch Client")
+
+ return
}
diff --git a/pkg/goexec/dcom/util.go b/pkg/goexec/dcom/util.go
index 5ed8a60..9d7850d 100644
--- a/pkg/goexec/dcom/util.go
+++ b/pkg/goexec/dcom/util.go
@@ -1,85 +1,88 @@
package dcomexec
import (
- "context"
- "fmt"
- "github.com/oiweiwei/go-msrpc/dcerpc"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut/idispatch/v0"
- "strings"
+ "context"
+ "fmt"
+ "github.com/oiweiwei/go-msrpc/dcerpc"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut"
+ "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut/idispatch/v0"
+ "strings"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
func callComMethod(ctx context.Context, dc idispatch.DispatchClient, method string, args ...*oaut.Variant) (ir *idispatch.InvokeResponse, err error) {
- parts := strings.Split(method, ".")
+ parts := strings.Split(method, ".")
- var id *dcom.IPID
- var gr *idispatch.GetIDsOfNamesResponse
+ var id *dcom.IPID
+ var gr *idispatch.GetIDsOfNamesResponse
- for i, obj := range parts {
+ for i, obj := range parts {
- var opts []dcerpc.CallOption
+ var opts []dcerpc.CallOption
- if id != nil {
- opts = append(opts, dcom.WithIPID(id))
- }
+ if id != nil {
+ opts = append(opts, dcom.WithIPID(id))
+ }
- gr, err = dc.GetIDsOfNames(ctx, &idispatch.GetIDsOfNamesRequest{
- This: ORPCThis,
- IID: &dcom.IID{},
- LocaleID: LcEnglishUs,
+ gr, err = dc.GetIDsOfNames(ctx, &idispatch.GetIDsOfNamesRequest{
+ This: ORPCThis,
+ IID: &dcom.IID{},
+ LocaleID: LcEnglishUs,
- Names: []string{obj + "\x00"},
- }, opts...)
+ Names: []string{obj + "\x00"},
+ }, opts...)
- if err != nil {
- return nil, fmt.Errorf("get dispatch ID of name %q: %w", obj, err)
- }
+ if err != nil {
+ return nil, fmt.Errorf("get dispatch ID of name %q: %w", obj, err)
+ }
- if len(gr.DispatchID) < 1 {
- return nil, fmt.Errorf("dispatch ID of name %q not found", obj)
- }
+ if len(gr.DispatchID) < 1 {
+ return nil, fmt.Errorf("dispatch ID of name %q not found", obj)
+ }
- irq := &idispatch.InvokeRequest{
- This: ORPCThis,
- IID: &dcom.IID{},
- LocaleID: LcEnglishUs,
+ irq := &idispatch.InvokeRequest{
+ This: ORPCThis,
+ IID: &dcom.IID{},
+ LocaleID: LcEnglishUs,
- DispatchIDMember: gr.DispatchID[0],
- }
+ DispatchIDMember: gr.DispatchID[0],
+ }
- if i >= len(parts)-1 {
- irq.Flags = 1
- irq.DispatchParams = &oaut.DispatchParams{ArgsCount: uint32(len(args)), Args: args}
- return dc.Invoke(ctx, irq, opts...)
- }
- irq.Flags = 2
+ if i >= len(parts)-1 {
+ irq.Flags = 1
+ irq.DispatchParams = &oaut.DispatchParams{ArgsCount: uint32(len(args)), Args: args}
+ return dc.Invoke(ctx, irq, opts...)
+ }
+ irq.Flags = 2
- ir, err = dc.Invoke(ctx, irq, opts...)
- if err != nil {
- return nil, fmt.Errorf("get properties of object %q: %w", obj, err)
- }
+ ir, err = dc.Invoke(ctx, irq, opts...)
+ if err != nil {
+ return nil, fmt.Errorf("get properties of object %q: %w", obj, err)
+ }
- di, ok := ir.VarResult.VarUnion.GetValue().(*oaut.Dispatch)
- if !ok {
- return nil, fmt.Errorf("invalid dispatch object for %q", obj)
- }
- id = di.InterfacePointer().GetStandardObjectReference().Std.IPID
- }
- return
+ di, ok := ir.VarResult.VarUnion.GetValue().(*oaut.Dispatch)
+ if !ok {
+ return nil, fmt.Errorf("invalid dispatch object for %q", obj)
+ }
+ id = di.InterfacePointer().GetStandardObjectReference().Std.IPID
+ }
+ return
}
func stringToVariant(s string) *oaut.Variant {
- return &oaut.Variant{
- Size: 5,
- VT: 8,
- VarUnion: &oaut.Variant_VarUnion{
- Value: &oaut.Variant_VarUnion_BSTR{
- BSTR: &oaut.String{
- Data: s,
- },
- },
- },
- }
+ return &oaut.Variant{
+ Size: 5,
+ VT: 8,
+ VarUnion: &oaut.Variant_VarUnion{
+ Value: &oaut.Variant_VarUnion_BSTR{
+ BSTR: &oaut.String{
+ Data: s,
+ },
+ },
+ },
+ }
}
diff --git a/pkg/goexec/scmr/create.go b/pkg/goexec/scmr/create.go
index b0f8774..f0245af 100644
--- a/pkg/goexec/scmr/create.go
+++ b/pkg/goexec/scmr/create.go
@@ -1,126 +1,129 @@
package scmrexec
import (
- "context"
- "fmt"
- "github.com/FalconOpsLLC/goexec/internal/util"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/oiweiwei/go-msrpc/msrpc/scmr/svcctl/v2"
- "github.com/rs/zerolog"
+ "context"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/internal/util"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/oiweiwei/go-msrpc/msrpc/scmr/svcctl/v2"
+ "github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
- MethodCreate = "Create"
+ MethodCreate = "Create"
)
type ScmrCreate struct {
- Scmr
- goexec.Cleaner
- goexec.Executor
+ Scmr
+ goexec.Cleaner
+ goexec.Executor
- IO goexec.ExecutionIO
+ IO goexec.ExecutionIO
- NoDelete bool
- NoStart bool
- ServiceName string
- DisplayName string
+ NoDelete bool
+ NoStart bool
+ ServiceName string
+ DisplayName string
}
func (m *ScmrCreate) ensure() {
- if m.ServiceName == "" {
- m.ServiceName = util.RandomString()
- }
- if m.DisplayName == "" {
- m.DisplayName = m.ServiceName
- }
+ if m.ServiceName == "" {
+ m.ServiceName = util.RandomString()
+ }
+ if m.DisplayName == "" {
+ m.DisplayName = m.ServiceName
+ }
}
func (m *ScmrCreate) Execute(ctx context.Context, in *goexec.ExecutionIO) (err error) {
- m.ensure()
-
- log := zerolog.Ctx(ctx).With().
- Str("service", m.ServiceName).Logger()
-
- svc := &service{name: m.ServiceName}
-
- resp, err := m.ctl.CreateServiceW(ctx, &svcctl.CreateServiceWRequest{
- ServiceManager: m.scm,
- ServiceName: m.ServiceName,
- DisplayName: m.DisplayName,
- BinaryPathName: in.String(),
- ServiceType: ServiceWin32OwnProcess,
- StartType: ServiceDemandStart,
- DesiredAccess: ServiceAllAccess, // TODO: Replace
- })
-
- if err != nil {
- log.Error().Err(err).Msg("Create service request failed")
- return fmt.Errorf("create service request: %w", err)
- }
-
- if resp.Return != 0 {
- log.Error().Err(err).Msg("Failed to create service")
- return fmt.Errorf("create service returned non-zero exit code: %02x", resp.Return)
- }
-
- if !m.NoDelete {
- m.AddCleaners(func(ctxInner context.Context) error {
-
- r, errInner := m.ctl.DeleteService(ctxInner, &svcctl.DeleteServiceRequest{
- Service: svc.handle,
- })
- if errInner != nil {
- return fmt.Errorf("delete service: %w", errInner)
- }
- if r.Return != 0 {
- return fmt.Errorf("delete service returned non-zero exit code: %02x", r.Return)
- }
- log.Info().Msg("Deleted service")
-
- return nil
- })
- }
-
- m.AddCleaners(func(ctxInner context.Context) error {
-
- r, errInner := m.ctl.CloseService(ctxInner, &svcctl.CloseServiceRequest{
- ServiceObject: svc.handle,
- })
- if errInner != nil {
- return fmt.Errorf("close service: %w", errInner)
- }
- if r.Return != 0 {
- return fmt.Errorf("close service returned non-zero exit code: %02x", r.Return)
- }
- log.Info().Msg("Closed service handle")
-
- return nil
- })
-
- log.Info().Msg("Created service")
- svc.handle = resp.Service
-
- if !m.NoStart {
-
- err = m.startService(ctx, svc)
-
- if err != nil {
- log.Error().Err(err).Msg("Failed to start service")
- return fmt.Errorf("start service: %w", err)
- }
- }
- if svc.handle == nil {
-
- if err = m.Reconnect(ctx); err != nil {
- return err
- }
- svc, err = m.openService(ctx, svc.name)
-
- if err != nil {
- log.Error().Err(err).Msg("Failed to reopen service handle")
- return fmt.Errorf("reopen service: %w", err)
- }
- }
-
- return
+ m.ensure()
+
+ log := zerolog.Ctx(ctx).With().
+ Str("service", m.ServiceName).Logger()
+
+ svc := &service{name: m.ServiceName}
+
+ resp, err := m.ctl.CreateServiceW(ctx, &svcctl.CreateServiceWRequest{
+ ServiceManager: m.scm,
+ ServiceName: m.ServiceName,
+ DisplayName: m.DisplayName,
+ BinaryPathName: in.String(),
+ ServiceType: ServiceWin32OwnProcess,
+ StartType: ServiceDemandStart,
+ DesiredAccess: ServiceAllAccess, // TODO: Replace
+ })
+
+ if err != nil {
+ log.Error().Err(err).Msg("Create service request failed")
+ return fmt.Errorf("create service request: %w", err)
+ }
+
+ if resp.Return != 0 {
+ log.Error().Err(err).Msg("Failed to create service")
+ return fmt.Errorf("create service returned non-zero exit code: %02x", resp.Return)
+ }
+
+ if !m.NoDelete {
+ m.AddCleaners(func(ctxInner context.Context) error {
+
+ r, errInner := m.ctl.DeleteService(ctxInner, &svcctl.DeleteServiceRequest{
+ Service: svc.handle,
+ })
+ if errInner != nil {
+ return fmt.Errorf("delete service: %w", errInner)
+ }
+ if r.Return != 0 {
+ return fmt.Errorf("delete service returned non-zero exit code: %02x", r.Return)
+ }
+ log.Info().Msg("Deleted service")
+
+ return nil
+ })
+ }
+
+ m.AddCleaners(func(ctxInner context.Context) error {
+
+ r, errInner := m.ctl.CloseService(ctxInner, &svcctl.CloseServiceRequest{
+ ServiceObject: svc.handle,
+ })
+ if errInner != nil {
+ return fmt.Errorf("close service: %w", errInner)
+ }
+ if r.Return != 0 {
+ return fmt.Errorf("close service returned non-zero exit code: %02x", r.Return)
+ }
+ log.Info().Msg("Closed service handle")
+
+ return nil
+ })
+
+ log.Info().Msg("Created service")
+ svc.handle = resp.Service
+
+ if !m.NoStart {
+
+ err = m.startService(ctx, svc)
+
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to start service")
+ return fmt.Errorf("start service: %w", err)
+ }
+ }
+ if svc.handle == nil {
+
+ if err = m.Reconnect(ctx); err != nil {
+ return err
+ }
+ svc, err = m.openService(ctx, svc.name)
+
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to reopen service handle")
+ return fmt.Errorf("reopen service: %w", err)
+ }
+ }
+
+ return
}
diff --git a/pkg/goexec/scmr/module.go b/pkg/goexec/scmr/module.go
index 708da23..56ce3fd 100644
--- a/pkg/goexec/scmr/module.go
+++ b/pkg/goexec/scmr/module.go
@@ -11,6 +11,9 @@ import (
"github.com/oiweiwei/go-msrpc/midl/uuid"
"github.com/oiweiwei/go-msrpc/msrpc/scmr/svcctl/v2"
"github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
type Scmr struct {
diff --git a/pkg/goexec/scmr/scmr.go b/pkg/goexec/scmr/scmr.go
index 4831ac7..696415b 100644
--- a/pkg/goexec/scmr/scmr.go
+++ b/pkg/goexec/scmr/scmr.go
@@ -42,10 +42,10 @@ const (
SERVICE_STOPPED uint32 = 0x00000001
*/
- ServiceDeleteAccess uint32 = ServiceDelete
- ServiceModifyAccess uint32 = ServiceQueryConfig | ServiceChangeConfig | ServiceStop | ServiceStart | ServiceDelete
- ServiceCreateAccess uint32 = ScManagerCreateService | ServiceStart | ServiceStop | ServiceDelete
- ServiceAllAccess uint32 = ServiceCreateAccess | ServiceModifyAccess
+ ServiceDeleteAccess = ServiceDelete
+ ServiceModifyAccess = ServiceQueryConfig | ServiceChangeConfig | ServiceStop | ServiceStart | ServiceDelete
+ ServiceCreateAccess = ScManagerCreateService | ServiceStart | ServiceStop | ServiceDelete
+ ServiceAllAccess = ServiceCreateAccess | ServiceModifyAccess
)
type service struct {
diff --git a/pkg/goexec/tsch/change.go b/pkg/goexec/tsch/change.go
index 44877c9..908b25a 100644
--- a/pkg/goexec/tsch/change.go
+++ b/pkg/goexec/tsch/change.go
@@ -1,152 +1,155 @@
package tschexec
import (
- "context"
- "encoding/xml"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/FalconOpsLLC/goexec/pkg/goexec/tsch/task"
- "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
- "github.com/rs/zerolog"
- "regexp"
- "time"
+ "context"
+ "encoding/xml"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec/tsch/task"
+ "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
+ "github.com/rs/zerolog"
+ "regexp"
+ "time"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
- FlagTaskUpdate uint32 = 0b_00000000_00000000_00000000_00000100
- MethodChange = "Change"
- DefaultWaitTime = 1 * time.Second
+ FlagTaskUpdate uint32 = 0b_00000000_00000000_00000000_00000100
+ MethodChange = "Change"
+ DefaultWaitTime = 1 * time.Second
)
type TschChange struct {
- Tsch
- goexec.Executor
- goexec.Cleaner
+ Tsch
+ goexec.Executor
+ goexec.Cleaner
- IO goexec.ExecutionIO
+ IO goexec.ExecutionIO
- WorkingDirectory string
- NoStart bool
- NoRevert bool
- WaitTime time.Duration
+ WorkingDirectory string
+ NoStart bool
+ NoRevert bool
+ WaitTime time.Duration
}
func (m *TschChange) Execute(ctx context.Context, execIO *goexec.ExecutionIO) (err error) {
- log := zerolog.Ctx(ctx).With().
- Str("module", ModuleName).
- Str("method", MethodChange).
- Str("task", m.TaskPath).
- Logger()
+ log := zerolog.Ctx(ctx).With().
+ Str("module", ModuleName).
+ Str("method", MethodChange).
+ Str("task", m.TaskPath).
+ Logger()
- retrieveResponse, err := m.tsch.RetrieveTask(ctx, &itaskschedulerservice.RetrieveTaskRequest{
- Path: m.TaskPath,
- })
+ retrieveResponse, err := m.tsch.RetrieveTask(ctx, &itaskschedulerservice.RetrieveTaskRequest{
+ Path: m.TaskPath,
+ })
- if err != nil {
- log.Error().Err(err).Msg("Failed to retrieve task")
- return fmt.Errorf("retrieve task: %w", err)
- }
- if retrieveResponse.Return != 0 {
- log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", retrieveResponse.Return)).
- Msg("Failed to retrieve task")
- return fmt.Errorf("retrieve task returned non-zero exit code: %02x", retrieveResponse.Return)
- }
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to retrieve task")
+ return fmt.Errorf("retrieve task: %w", err)
+ }
+ if retrieveResponse.Return != 0 {
+ log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", retrieveResponse.Return)).
+ Msg("Failed to retrieve task")
+ return fmt.Errorf("retrieve task returned non-zero exit code: %02x", retrieveResponse.Return)
+ }
- log.Info().Msg("Successfully retrieved existing task definition")
- log.Debug().Str("xml", retrieveResponse.XML).Msg("Got task definition")
+ log.Info().Msg("Successfully retrieved existing task definition")
+ log.Debug().Str("xml", retrieveResponse.XML).Msg("Got task definition")
- tk := task.Task{}
+ tk := task.Task{}
- enc := regexp.MustCompile(`(?i)^<\?xml .*?\?>`)
- tkStr := enc.ReplaceAllString(retrieveResponse.XML, `<?xml version="1.0" encoding="utf-8"?>`)
+ enc := regexp.MustCompile(`(?i)^<\?xml .*?\?>`)
+ tkStr := enc.ReplaceAllString(retrieveResponse.XML, `<?xml version="1.0" encoding="utf-8"?>`)
- if err = xml.Unmarshal([]byte(tkStr), &tk); err != nil {
- log.Error().Err(err).Msg("Failed to unmarshal task XML")
+ if err = xml.Unmarshal([]byte(tkStr), &tk); err != nil {
+ log.Error().Err(err).Msg("Failed to unmarshal task XML")
- return fmt.Errorf("unmarshal task XML: %w", err)
- }
+ return fmt.Errorf("unmarshal task XML: %w", err)
+ }
- cmd := execIO.CommandLine()
+ cmd := execIO.CommandLine()
- tk.Actions.Exec = append(tk.Actions.Exec, task.ExecAction{
- Command: cmd[0],
- Arguments: cmd[1],
- WorkingDirectory: m.WorkingDirectory,
- })
+ tk.Actions.Exec = append(tk.Actions.Exec, task.ExecAction{
+ Command: cmd[0],
+ Arguments: cmd[1],
+ WorkingDirectory: m.WorkingDirectory,
+ })
- doc, err := xml.Marshal(tk)
+ doc, err := xml.Marshal(tk)
- if err != nil {
- log.Error().Err(err).Msg("failed to marshal task XML")
- return fmt.Errorf("marshal task: %w", err)
- }
+ if err != nil {
+ log.Error().Err(err).Msg("failed to marshal task XML")
+ return fmt.Errorf("marshal task: %w", err)
+ }
- taskXml := TaskXmlHeader + string(doc)
- log.Debug().Str("xml", taskXml).Msg("Serialized new task")
+ taskXml := TaskXmlHeader + string(doc)
+ log.Debug().Str("xml", taskXml).Msg("Serialized new task")
- registerResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
- Path: m.TaskPath,
- XML: taskXml,
- Flags: FlagTaskUpdate,
- })
+ registerResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
+ Path: m.TaskPath,
+ XML: taskXml,
+ Flags: FlagTaskUpdate,
+ })
- if !m.NoRevert {
+ if !m.NoRevert {
- m.AddCleaners(func(ctxInner context.Context) error {
+ m.AddCleaners(func(ctxInner context.Context) error {
- revertResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
- Path: m.TaskPath,
- XML: retrieveResponse.XML,
- Flags: FlagTaskUpdate,
- })
+ revertResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
+ Path: m.TaskPath,
+ XML: retrieveResponse.XML,
+ Flags: FlagTaskUpdate,
+ })
- if err != nil {
- return err
- }
- if revertResponse.Return != 0 {
- return fmt.Errorf("revert task definition returned non-zero exit code: %02x", revertResponse.Return)
- }
- return nil
- })
- }
+ if err != nil {
+ return err
+ }
+ if revertResponse.Return != 0 {
+ return fmt.Errorf("revert task definition returned non-zero exit code: %02x", revertResponse.Return)
+ }
+ return nil
+ })
+ }
- if err != nil {
- log.Error().Err(err).Msg("Failed to update task")
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to update task")
- return fmt.Errorf("update task: %w", err)
- }
- if registerResponse.Return != 0 {
- log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", registerResponse.Return)).Msg("Failed to update task definition")
+ return fmt.Errorf("update task: %w", err)
+ }
+ if registerResponse.Return != 0 {
+ log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", registerResponse.Return)).Msg("Failed to update task definition")
- return fmt.Errorf("update task returned non-zero exit code: %02x", registerResponse.Return)
- }
- log.Info().Msg("Successfully updated task definition")
+ return fmt.Errorf("update task returned non-zero exit code: %02x", registerResponse.Return)
+ }
+ log.Info().Msg("Successfully updated task definition")
- if !m.NoStart {
+ if !m.NoStart {
- runResponse, err := m.tsch.Run(ctx, &itaskschedulerservice.RunRequest{
- Path: m.TaskPath,
- })
+ runResponse, err := m.tsch.Run(ctx, &itaskschedulerservice.RunRequest{
+ Path: m.TaskPath,
+ })
- if err != nil {
- log.Error().Err(err).Msg("Failed to run modified task")
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to run modified task")
- return fmt.Errorf("run task: %w", err)
- }
+ return fmt.Errorf("run task: %w", err)
+ }
- if ret := uint32(runResponse.Return); ret != 0 {
- log.Error().Str("code", fmt.Sprintf("0x%08x", ret)).Msg("Run task returned non-zero exit code")
+ if ret := uint32(runResponse.Return); ret != 0 {
+ log.Error().Str("code", fmt.Sprintf("0x%08x", ret)).Msg("Run task returned non-zero exit code")
- return fmt.Errorf("run task returned non-zero exit code: 0x%08x", ret)
- }
+ return fmt.Errorf("run task returned non-zero exit code: 0x%08x", ret)
+ }
- log.Info().Msg("Successfully started modified task")
- }
+ log.Info().Msg("Successfully started modified task")
+ }
- if m.WaitTime <= 0 {
- m.WaitTime = DefaultWaitTime
- }
- time.Sleep(m.WaitTime)
- return
+ if m.WaitTime <= 0 {
+ m.WaitTime = DefaultWaitTime
+ }
+ time.Sleep(m.WaitTime)
+ return
}
diff --git a/pkg/goexec/tsch/demand.go b/pkg/goexec/tsch/demand.go
index 74a41fe..62e546f 100644
--- a/pkg/goexec/tsch/demand.go
+++ b/pkg/goexec/tsch/demand.go
@@ -1,81 +1,84 @@
package tschexec
import (
- "context"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
- "github.com/rs/zerolog"
+ "context"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
+ "github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
- MethodDemand = "Demand"
+ MethodDemand = "Demand"
)
type TschDemand struct {
- Tsch
- goexec.Executor
- goexec.Cleaner
+ Tsch
+ goexec.Executor
+ goexec.Cleaner
- IO goexec.ExecutionIO
+ IO goexec.ExecutionIO
- NoDelete bool
- NoStart bool
- SessionId uint32
+ NoDelete bool
+ NoStart bool
+ SessionId uint32
}
func (m *TschDemand) Execute(ctx context.Context, execIO *goexec.ExecutionIO) (err error) {
- log := zerolog.Ctx(ctx).With().
- Str("module", ModuleName).
- Str("method", MethodDemand).
- Str("task", m.TaskPath).
- Logger()
-
- path, err := m.registerTask(ctx,
- &registerOptions{
- AllowStartOnDemand: true,
- AllowHardTerminate: true,
- Hidden: !m.NotHidden,
- triggers: taskTriggers{},
- },
- execIO,
- )
- if err != nil {
- return err
- }
-
- log.Info().Msg("Task registered")
-
- if !m.NoDelete {
- m.AddCleaners(func(ctxInner context.Context) error {
- return m.deleteTask(ctxInner, path)
- })
- }
-
- if !m.NoStart {
-
- var flags uint32
- if m.SessionId != 0 {
- flags |= 4
- }
-
- runResponse, err := m.tsch.Run(ctx, &itaskschedulerservice.RunRequest{
- Path: path,
- Flags: flags,
- SessionID: m.SessionId,
- })
-
- if err != nil {
- log.Error().Err(err).Msg("Failed to run task")
- return fmt.Errorf("run task: %w", err)
- }
- if ret := uint32(runResponse.Return); ret != 0 {
- log.Error().Str("code", fmt.Sprintf("0x%08x", ret)).Msg("Task returned non-zero exit code")
- return fmt.Errorf("task returned non-zero exit code: 0x%08x", ret)
- }
-
- log.Info().Msg("Task started successfully")
- }
- return
+ log := zerolog.Ctx(ctx).With().
+ Str("module", ModuleName).
+ Str("method", MethodDemand).
+ Str("task", m.TaskPath).
+ Logger()
+
+ path, err := m.registerTask(ctx,
+ &registerOptions{
+ AllowStartOnDemand: true,
+ AllowHardTerminate: true,
+ Hidden: !m.NotHidden,
+ triggers: taskTriggers{},
+ },
+ execIO,
+ )
+ if err != nil {
+ return err
+ }
+
+ log.Info().Msg("Task registered")
+
+ if !m.NoDelete {
+ m.AddCleaners(func(ctxInner context.Context) error {
+ return m.deleteTask(ctxInner, path)
+ })
+ }
+
+ if !m.NoStart {
+
+ var flags uint32
+ if m.SessionId != 0 {
+ flags |= 4
+ }
+
+ runResponse, err := m.tsch.Run(ctx, &itaskschedulerservice.RunRequest{
+ Path: path,
+ Flags: flags,
+ SessionID: m.SessionId,
+ })
+
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to run task")
+ return fmt.Errorf("run task: %w", err)
+ }
+ if ret := uint32(runResponse.Return); ret != 0 {
+ log.Error().Str("code", fmt.Sprintf("0x%08x", ret)).Msg("Task returned non-zero exit code")
+ return fmt.Errorf("task returned non-zero exit code: 0x%08x", ret)
+ }
+
+ log.Info().Msg("Task started successfully")
+ }
+ return
}
diff --git a/pkg/goexec/tsch/module.go b/pkg/goexec/tsch/module.go
index 677856d..6ca4cca 100644
--- a/pkg/goexec/tsch/module.go
+++ b/pkg/goexec/tsch/module.go
@@ -1,163 +1,166 @@
package tschexec
import (
- "context"
- "encoding/xml"
- "errors"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
- "github.com/oiweiwei/go-msrpc/dcerpc"
- "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
- "github.com/rs/zerolog"
+ "context"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec/dce"
+ "github.com/oiweiwei/go-msrpc/dcerpc"
+ "github.com/oiweiwei/go-msrpc/msrpc/tsch/itaskschedulerservice/v1"
+ "github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
- ModuleName = "TSCH"
+ ModuleName = "TSCH"
)
type Tsch struct {
- goexec.Cleaner
+ goexec.Cleaner
- Client *dce.Client
- tsch itaskschedulerservice.TaskSchedulerServiceClient
+ Client *dce.Client
+ tsch itaskschedulerservice.TaskSchedulerServiceClient
- TaskPath string
- UserSid string
- NotHidden bool
+ TaskPath string
+ UserSid string
+ NotHidden bool
}
type registerOptions struct {
- AllowStartOnDemand bool
- AllowHardTerminate bool
- StartWhenAvailable bool
- Hidden bool
- DeleteAfter string
+ AllowStartOnDemand bool
+ AllowHardTerminate bool
+ StartWhenAvailable bool
+ Hidden bool
+ DeleteAfter string
- triggers taskTriggers
+ triggers taskTriggers
}
func (m *Tsch) Connect(ctx context.Context) (err error) {
- if err = m.Client.Connect(ctx); err == nil {
- m.AddCleaners(m.Client.Close)
- }
- return
+ if err = m.Client.Connect(ctx); err == nil {
+ m.AddCleaners(m.Client.Close)
+ }
+ return
}
func (m *Tsch) Init(ctx context.Context) (err error) {
- if m.Client.Dce() == nil {
- return errors.New("DCE connection not initialized")
- }
+ if m.Client.Dce() == nil {
+ return errors.New("DCE connection not initialized")
+ }
- // Create ITaskSchedulerService Client
- m.tsch, err = itaskschedulerservice.NewTaskSchedulerServiceClient(ctx, m.Client.Dce(), dcerpc.WithSeal())
- return
+ // Create ITaskSchedulerService Client
+ m.tsch, err = itaskschedulerservice.NewTaskSchedulerServiceClient(ctx, m.Client.Dce(), dcerpc.WithSeal())
+ return
}
func (m *Tsch) registerTask(ctx context.Context, opts *registerOptions, in *goexec.ExecutionIO) (path string, err error) {
- log := zerolog.Ctx(ctx).With().
- Str("task", m.TaskPath).
- Logger()
-
- ctx = log.WithContext(ctx)
-
- principalId := "LocalSystem"
-
- settings := taskSettings{
- MultipleInstancesPolicy: "IgnoreNew",
- IdleSettings: taskIdleSettings{
- StopOnIdleEnd: true,
- RestartOnIdle: false,
- },
- Enabled: true,
- Priority: 7, // a pretty standard value for scheduled tasks
- AllowHardTerminate: opts.AllowHardTerminate,
- AllowStartOnDemand: opts.AllowStartOnDemand,
- Hidden: opts.Hidden,
- StartWhenAvailable: opts.StartWhenAvailable,
- DeleteExpiredTaskAfter: opts.DeleteAfter,
- }
-
- principals := taskPrincipals{
- Principals: []taskPrincipal{
- {
- ID: principalId,
- UserID: m.UserSid,
- RunLevel: "HighestAvailable",
- },
- }}
-
- cmdline := in.CommandLine()
-
- actions := taskActions{
- Context: principalId,
- Exec: []taskActionExec{
- {
- Command: cmdline[0],
- Arguments: cmdline[1],
- },
- },
- }
-
- def := simpleTask{
- TaskVersion: TaskXmlVersion,
- TaskNamespace: TaskXmlNamespace,
- Triggers: opts.triggers,
- Actions: actions,
- Principals: principals,
- Settings: settings,
- }
-
- // Generate task XML content. See https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/0d6383e4-de92-43e7-b0bb-a60cfa36379f
-
- doc, err := xml.Marshal(def)
-
- if err != nil {
- log.Error().Err(err).Msg("failed to marshal task XML")
- return "", fmt.Errorf("marshal task: %w", err)
- }
-
- taskXml := TaskXmlHeader + string(doc)
-
- log.Debug().Str("content", taskXml).Msg("Generated task XML")
-
- registerResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
- Path: m.TaskPath,
- XML: taskXml,
- Flags: 0, // FEATURE: dynamic
- SDDL: "",
- LogonType: 0, // FEATURE: dynamic
- CredsCount: 0,
- Creds: nil,
- })
-
- if err != nil {
- log.Error().Err(err).Msg("Failed to register task")
- return "", fmt.Errorf("register task: %w", err)
- }
- log.Info().Msg("Scheduled task registered")
-
- return registerResponse.ActualPath, nil
+ log := zerolog.Ctx(ctx).With().
+ Str("task", m.TaskPath).
+ Logger()
+
+ ctx = log.WithContext(ctx)
+
+ principalId := "LocalSystem"
+
+ settings := taskSettings{
+ MultipleInstancesPolicy: "IgnoreNew",
+ IdleSettings: taskIdleSettings{
+ StopOnIdleEnd: true,
+ RestartOnIdle: false,
+ },
+ Enabled: true,
+ Priority: 7, // a pretty standard value for scheduled tasks
+ AllowHardTerminate: opts.AllowHardTerminate,
+ AllowStartOnDemand: opts.AllowStartOnDemand,
+ Hidden: opts.Hidden,
+ StartWhenAvailable: opts.StartWhenAvailable,
+ DeleteExpiredTaskAfter: opts.DeleteAfter,
+ }
+
+ principals := taskPrincipals{
+ Principals: []taskPrincipal{
+ {
+ ID: principalId,
+ UserID: m.UserSid,
+ RunLevel: "HighestAvailable",
+ },
+ }}
+
+ cmdline := in.CommandLine()
+
+ actions := taskActions{
+ Context: principalId,
+ Exec: []taskActionExec{
+ {
+ Command: cmdline[0],
+ Arguments: cmdline[1],
+ },
+ },
+ }
+
+ def := simpleTask{
+ TaskVersion: TaskXmlVersion,
+ TaskNamespace: TaskXmlNamespace,
+ Triggers: opts.triggers,
+ Actions: actions,
+ Principals: principals,
+ Settings: settings,
+ }
+
+ // Generate task XML content. See https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/0d6383e4-de92-43e7-b0bb-a60cfa36379f
+
+ doc, err := xml.Marshal(def)
+
+ if err != nil {
+ log.Error().Err(err).Msg("failed to marshal task XML")
+ return "", fmt.Errorf("marshal task: %w", err)
+ }
+
+ taskXml := TaskXmlHeader + string(doc)
+
+ log.Debug().Str("content", taskXml).Msg("Generated task XML")
+
+ registerResponse, err := m.tsch.RegisterTask(ctx, &itaskschedulerservice.RegisterTaskRequest{
+ Path: m.TaskPath,
+ XML: taskXml,
+ Flags: 0, // FEATURE: dynamic
+ SDDL: "",
+ LogonType: 0, // FEATURE: dynamic
+ CredsCount: 0,
+ Creds: nil,
+ })
+
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to register task")
+ return "", fmt.Errorf("register task: %w", err)
+ }
+ log.Info().Msg("Scheduled task registered")
+
+ return registerResponse.ActualPath, nil
}
func (m *Tsch) deleteTask(ctx context.Context, taskPath string) (err error) {
- log := zerolog.Ctx(ctx).With().
- Str("path", taskPath).Logger()
+ log := zerolog.Ctx(ctx).With().
+ Str("path", taskPath).Logger()
- _, err = m.tsch.Delete(ctx, &itaskschedulerservice.DeleteRequest{
- Path: taskPath,
- })
+ _, err = m.tsch.Delete(ctx, &itaskschedulerservice.DeleteRequest{
+ Path: taskPath,
+ })
- if err != nil {
- log.Error().Err(err).Msg("Failed to delete task")
- return fmt.Errorf("delete task: %w", err)
- }
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to delete task")
+ return fmt.Errorf("delete task: %w", err)
+ }
- log.Info().Msg("Task deleted")
+ log.Info().Msg("Task deleted")
- return
+ return
}
diff --git a/pkg/goexec/tsch/task/action.go b/pkg/goexec/tsch/task/action.go
index de6c29f..903c633 100644
--- a/pkg/goexec/tsch/task/action.go
+++ b/pkg/goexec/tsch/task/action.go
@@ -85,7 +85,7 @@ type ShowMessageAction struct {
// NamedValues holds zero or more <Value name="…">…</Value> entries.
type NamedValues struct {
- XMLName xml.Name `xml:"HeaderFields"`
+ XMLName xml.Name //`xml:"HeaderFields"`
Value []NamedValue `xml:"Value"`
}
diff --git a/pkg/goexec/tsch/tsch.go b/pkg/goexec/tsch/tsch.go
index ae65ca7..3cbcb2c 100644
--- a/pkg/goexec/tsch/tsch.go
+++ b/pkg/goexec/tsch/tsch.go
@@ -92,6 +92,8 @@ type simpleTask struct {
Settings taskSettings `xml:"Settings"`
}
+/*
+
// newSettings just creates a taskSettings instance with the necessary values + a few dynamic ones
func newSettings(terminate, onDemand, startWhenAvailable bool) *taskSettings {
return &taskSettings{
@@ -140,6 +142,7 @@ func newTask(se *taskSettings, pr []taskPrincipal, tr taskTriggers, cmd, args st
},
}
}
+*/
// xmlDuration is a *very* simple implementation of xs:duration - only accepts +seconds
func xmlDuration(dur time.Duration) string {
diff --git a/pkg/goexec/wmi/module.go b/pkg/goexec/wmi/module.go
index 90bbaa8..3ae98cc 100644
--- a/pkg/goexec/wmi/module.go
+++ b/pkg/goexec/wmi/module.go
@@ -14,6 +14,10 @@ import (
"github.com/oiweiwei/go-msrpc/msrpc/dcom/wmi/iwbemservices/v0"
"github.com/oiweiwei/go-msrpc/msrpc/dcom/wmio/query"
"github.com/rs/zerolog"
+
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
+ _ "github.com/oiweiwei/go-msrpc/msrpc/erref/wmi"
)
const (
@@ -72,8 +76,7 @@ func (m *Wmi) Init(ctx context.Context) (err error) {
var newOpts []dcerpc.Option
for _, bind := range actResponse.OXIDBindings.GetStringBindings() {
- stringBinding, err := dcerpc.ParseStringBinding("ncacn_ip_tcp:" + bind.NetworkAddr) // TODO: try bind.String()
-
+ stringBinding, err := dcerpc.ParseStringBinding(bind.String())
if err != nil {
log.Debug().Err(err).Msg("Failed to parse string binding")
continue
@@ -102,13 +105,13 @@ func (m *Wmi) Init(ctx context.Context) (err error) {
NetworkResource: m.Resource,
})
- log.Info().Msg("Completed NTLMLogin operation")
-
if err != nil {
log.Error().Err(err).Msg("Failed to login on remote instance")
return fmt.Errorf("login: IWbemLevel1Login::NTLMLogin: %w", err)
}
+ log.Info().Msg("Completed NTLMLogin operation")
+
ipid = login.Namespace.InterfacePointer().IPID()
m.servicesClient, err = iwbemservices.NewServicesClient(ctx, m.Client.Dce(), dcom.WithIPID(ipid))
@@ -122,9 +125,7 @@ func (m *Wmi) Init(ctx context.Context) (err error) {
return
}
-func (m *Wmi) query(ctx context.Context, class, method string, values map[string]any) (outValues map[string]any, err error) {
- outValues = make(map[string]any)
-
+func (m *Wmi) query(ctx context.Context, class, method string, values map[string]any) (map[string]any, error) {
if m.servicesClient == nil {
return nil, errors.New("module has not been initialized")
}