aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/dcom.go89
-rw-r--r--cmd/root.go342
-rw-r--r--cmd/scmr.go15
-rw-r--r--cmd/tsch.go11
-rw-r--r--cmd/wmi.go213
-rw-r--r--go.mod3
-rw-r--r--go.sum19
-rw-r--r--pkg/goexec/dcom/mmc.go68
-rw-r--r--pkg/goexec/dcom/module.go211
9 files changed, 503 insertions, 468 deletions
diff --git a/cmd/dcom.go b/cmd/dcom.go
index c671252..f4e4f91 100644
--- a/cmd/dcom.go
+++ b/cmd/dcom.go
@@ -1,62 +1,63 @@
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() {
- registerRpcFlags(dcomCmd)
- dcomMmcCmdInit()
- dcomCmd.AddCommand(dcomMmcCmd)
+ registerRpcFlags(dcomCmd)
+ dcomMmcCmdInit()
+ dcomCmd.AddCommand(dcomMmcCmd)
}
func dcomMmcCmdInit() {
- dcomMmcCmd.Flags().StringVarP(&dcomMmc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
- dcomMmcCmd.Flags().StringVar(&dcomMmc.WindowState, "window", "Minimized", "Window state")
+ dcomMmcCmd.Flags().StringVarP(&dcomMmc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
+ dcomMmcCmd.Flags().StringVar(&dcomMmc.WindowState, "window", "Minimized", "Window state")
- registerProcessExecutionArgs(dcomMmcCmd)
- registerExecutionOutputArgs(dcomMmcCmd)
+ registerProcessExecutionArgs(dcomMmcCmd)
+ registerExecutionOutputArgs(dcomMmcCmd)
}
var (
- dcomMmc dcomexec.DcomMmc
-
- dcomCmd = &cobra.Command{
- Use: "dcom",
- Short: "Establish execution via DCOM",
- Args: cobra.NoArgs,
- }
-
- dcomMmcCmd = &cobra.Command{
- Use: "mmc [target]",
- Short: "Establish execution via the DCOM MMC20.Application object",
- Long: `Description:
+ dcomMmc dcomexec.DcomMmc
+
+ dcomCmd = &cobra.Command{
+ Use: "dcom",
+ Short: "Execute with Distributed Component Object Model (MS-DCOM)",
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
+
+ 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 execute system commands.
+ and ultimately spawn a process on the remote host.
References:
- https://www.scorpiones.io/articles/lateral-movement-using-dcom-objects
- https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/
- https://github.com/fortra/impacket/blob/master/examples/dcomexec.py
- https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/view-executeshellcommand
+ - https://www.scorpiones.io/articles/lateral-movement-using-dcom-objects
+ - https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/
+ - https://github.com/fortra/impacket/blob/master/examples/dcomexec.py
+ - https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/view-executeshellcommand
`,
- Args: args(
- argsRpcClient("host"),
- argsOutput("smb"),
- ),
- Run: func(cmd *cobra.Command, args []string) {
- dcomMmc.Dcom.Client = &rpcClient
- dcomMmc.IO = exec
-
- ctx := log.WithContext(gssapi.NewSecurityContext(context.TODO()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &dcomMmc, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ Args: args(
+ argsRpcClient("host"),
+ argsOutput("smb"),
+ ),
+ Run: func(cmd *cobra.Command, args []string) {
+ dcomMmc.Dcom.Client = &rpcClient
+ dcomMmc.IO = exec
+
+ ctx := log.WithContext(gssapi.NewSecurityContext(context.TODO()))
+
+ 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 300588d..815730e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,167 +1,201 @@
package cmd
import (
- "fmt"
- "github.com/FalconOpsLLC/goexec/internal/util"
- "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/oiweiwei/go-msrpc/ssp"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/rs/zerolog"
- "github.com/spf13/cobra"
- "github.com/spf13/pflag"
- "io"
- "os"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/internal/util"
+ "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/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"
)
var (
- returnCode int
- outputMethod string
- outputPath string
- proxy 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
- // ===============
-
- rpcClient dce.Client
- smbClient smb.Client
-
- 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: `Windows remote execution multitool`,
- Long: ``,
-
- 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
- }
- 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)
- }
-
- if proxy != "" {
- rpcClient.Proxy = proxy
- smbClient.Proxy = proxy
- }
-
- if outputPath != "" {
- if outputMethod == "smb" {
- if exec.Output.RemotePath == "" {
- exec.Output.RemotePath = util.RandomWindowsTempFile()
- }
- exec.Output.Provider = &smb.OutputFileFetcher{
- Client: &smbClient,
- Share: `C$`,
- File: exec.Output.RemotePath,
- DeleteOutputFile: !exec.Output.NoDelete,
- }
- }
- }
- return
- },
-
- PersistentPostRun: func(cmd *cobra.Command, args []string) {
- if err := logFile.Close(); err != nil {
- // ...
- }
- },
- }
+ flagGroups = map[string]*pflag.FlagSet{}
+
+ returnCode int
+ outputMethod string
+ outputPath string
+ proxy 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
+ // ===============
+
+ rpcClient dce.Client
+ smbClient smb.Client
+
+ 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: `Windows remote execution multitool`,
+ Long: ``,
+
+ 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
+ }
+ 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)
+ }
+
+ if proxy != "" {
+ rpcClient.Proxy = proxy
+ smbClient.Proxy = proxy
+ }
+
+ if outputPath != "" {
+ if outputMethod == "smb" {
+ if exec.Output.RemotePath == "" {
+ exec.Output.RemotePath = util.RandomWindowsTempFile()
+ }
+ exec.Output.Provider = &smb.OutputFileFetcher{
+ Client: &smbClient,
+ Share: `C$`,
+ File: exec.Output.RemotePath,
+ DeleteOutputFile: !exec.Output.NoDelete,
+ }
+ }
+ }
+ return
+ },
+
+ PersistentPostRun: func(cmd *cobra.Command, args []string) {
+ if err := logFile.Close(); err != nil {
+ // ...
+ }
+ },
+ }
)
+func addFlagSet(fs *pflag.FlagSet) {
+ flagGroups[fs.Name()] = fs
+}
+
+func moduleFlags(cmd *cobra.Command, module string) (fs *pflag.FlagSet) {
+ fs, _ = flagGroups[module]
+ return
+}
+
+// Uses the users terminal size or width of 80 if cannot determine users width
+// Based on https://github.com/spf13/cobra/issues/1805#issuecomment-1246192724
+func wrappedFlagUsages(cmd *pflag.FlagSet) string {
+ fd := int(os.Stdout.Fd())
+ width := 80
+
+ // Get the terminal width and dynamically set
+ termWidth, _, err := term.GetSize(fd)
+ if err == nil {
+ width = termWidth
+ }
+
+ return cmd.FlagUsagesWrapped(width - 1)
+}
+
func init() {
- // Auth init
- {
- gssapi.AddMechanism(ssp.SPNEGO)
- gssapi.AddMechanism(ssp.NTLM)
- gssapi.AddMechanism(ssp.KRB5)
- }
-
- // Cobra init
- {
- cobra.EnableCommandSorting = false
-
- rootCmd.InitDefaultVersionFlag()
- rootCmd.InitDefaultHelpCmd()
-
- // Logging flags
- {
- logOpts := pflag.NewFlagSet("Logging", pflag.ExitOnError)
- logOpts.BoolVar(&logDebug, "debug", false, "Enable debug logging")
- logOpts.BoolVar(&logJson, "json", false, "Write logging output in JSON lines")
- logOpts.BoolVar(&logQuiet, "quiet", false, "Disable info logging")
- logOpts.StringVarP(&logOutput, "log-file", "O", "", "Write JSON logging output to file")
- rootCmd.PersistentFlags().AddFlagSet(logOpts)
- }
-
- // Global networking flags
- {
- netOpts := pflag.NewFlagSet("Network", pflag.ExitOnError)
- netOpts.StringVarP(&proxy, "proxy", "x", "", "Proxy URL")
- rootCmd.PersistentFlags().AddFlagSet(netOpts)
- }
-
- // Authentication flags
- {
- adAuthOpts = &adauth.Options{
- Debug: log.Debug().Msgf,
- }
- authOpts := pflag.NewFlagSet("Authentication", pflag.ExitOnError)
- adAuthOpts.RegisterFlags(authOpts)
- rootCmd.PersistentFlags().AddFlagSet(authOpts)
- }
-
- // 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)
+ }
+
+ // Cobra init
+ {
+ cobra.EnableCommandSorting = false
+
+ rootCmd.InitDefaultVersionFlag()
+ rootCmd.InitDefaultHelpCmd()
+
+ modules := &cobra.Group{
+ ID: "module",
+ Title: "Execution Modules:",
+ }
+ rootCmd.AddGroup(modules)
+
+ // Logging flags
+ {
+ logOpts := pflag.NewFlagSet("Logging", pflag.ExitOnError)
+ logOpts.BoolVar(&logDebug, "debug", false, "Enable debug logging")
+ logOpts.BoolVar(&logJson, "json", false, "Write logging output in JSON lines")
+ logOpts.BoolVar(&logQuiet, "quiet", false, "Disable info logging")
+ logOpts.StringVarP(&logOutput, "log-file", "O", "", "Write JSON logging output to file")
+ rootCmd.PersistentFlags().AddFlagSet(logOpts)
+ flagGroups["Logging"] = logOpts
+ }
+
+ // Global networking flags
+ {
+ netOpts := pflag.NewFlagSet("Network", pflag.ExitOnError)
+ netOpts.StringVarP(&proxy, "proxy", "x", "", "Proxy URL")
+ rootCmd.PersistentFlags().AddFlagSet(netOpts)
+ }
+
+ // Authentication flags
+ {
+ adAuthOpts = &adauth.Options{
+ Debug: log.Debug().Msgf,
+ }
+ authOpts := pflag.NewFlagSet("Authentication", pflag.ExitOnError)
+ adAuthOpts.RegisterFlags(authOpts)
+ rootCmd.PersistentFlags().AddFlagSet(authOpts)
+ }
+
+ // 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/scmr.go b/cmd/scmr.go
index 08e23d7..b67b2a6 100644
--- a/cmd/scmr.go
+++ b/cmd/scmr.go
@@ -64,20 +64,21 @@ var (
scmrDelete scmrexec.ScmrDelete
scmrCmd = &cobra.Command{
- Use: "scmr",
- Short: "Establish execution via SCMR",
- Args: cobra.NoArgs,
+ Use: "scmr",
+ Short: "Execute with Service Control Manager Remote (MS-SCMR)",
+ GroupID: "module",
+ Args: cobra.NoArgs,
}
scmrCreateCmd = &cobra.Command{
Use: "create [target]",
- Short: "Create & run a new Windows service to gain execution",
+ Short: "Spawn a remote process by creating & running a Windows service",
Long: `Description:
- The create method calls RCreateServiceW to create a new Windows service with
- the provided executable & arguments as the lpBinaryPathName
+ The create method calls RCreateServiceW to create a new Windows service on the
+ remote target with the provided executable & arguments as the lpBinaryPathName
References:
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e
+ - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e
`,
Args: argsRpcClient("cifs"),
diff --git a/cmd/tsch.go b/cmd/tsch.go
index a647f06..0ed5d9f 100644
--- a/cmd/tsch.go
+++ b/cmd/tsch.go
@@ -64,9 +64,10 @@ var (
tschTask string
tschCmd = &cobra.Command{
- Use: "tsch",
- Short: "Establish execution via Windows Task Scheduler (MS-TSCH)",
- Args: cobra.NoArgs,
+ Use: "tsch",
+ Short: "Execute with Windows Task Scheduler (MS-TSCH)",
+ GroupID: "module",
+ Args: cobra.NoArgs,
}
tschDemandCmd = &cobra.Command{
@@ -78,8 +79,8 @@ var (
additionally call SchRpcRun to forcefully start the task.
References:
- SchRpcRegisterTask - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/849c131a-64e4-46ef-b015-9d4c599c5167
- SchRpcRun - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/77f2250d-500a-40ee-be18-c82f7079c4f0
+ - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/849c131a-64e4-46ef-b015-9d4c599c5167
+ - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/77f2250d-500a-40ee-be18-c82f7079c4f0
`,
Args: args(
argsRpcClient("cifs"),
diff --git a/cmd/wmi.go b/cmd/wmi.go
index 6bd003e..5e2d279 100644
--- a/cmd/wmi.go
+++ b/cmd/wmi.go
@@ -1,117 +1,118 @@
package cmd
import (
- "context"
- "encoding/json"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- wmiexec "github.com/FalconOpsLLC/goexec/pkg/goexec/wmi"
- "github.com/oiweiwei/go-msrpc/ssp/gssapi"
- "github.com/spf13/cobra"
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ wmiexec "github.com/FalconOpsLLC/goexec/pkg/goexec/wmi"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/spf13/cobra"
)
func wmiCmdInit() {
- registerRpcFlags(wmiCmd)
+ registerRpcFlags(wmiCmd)
- wmiCallCmdInit()
- wmiCmd.AddCommand(wmiCallCmd)
+ wmiCallCmdInit()
+ wmiCmd.AddCommand(wmiCallCmd)
- wmiProcCmdInit()
- wmiCmd.AddCommand(wmiProcCmd)
+ wmiProcCmdInit()
+ wmiCmd.AddCommand(wmiProcCmd)
}
func wmiCallArgs(_ *cobra.Command, _ []string) error {
- return json.Unmarshal([]byte(wmiArguments), &wmiCall.Args)
+ return json.Unmarshal([]byte(wmiArguments), &wmiCall.Args)
}
func wmiCallCmdInit() {
- wmiCallCmd.Flags().StringVarP(&wmiCall.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
- wmiCallCmd.Flags().StringVarP(&wmiCall.Class, "class", "C", "", `WMI class to instantiate (i.e. "Win32_Process")`)
- wmiCallCmd.Flags().StringVarP(&wmiCall.Method, "method", "m", "", `WMI Method to call (i.e. "Create")`)
- wmiCallCmd.Flags().StringVarP(&wmiArguments, "args", "A", "{}", `WMI Method argument(s) in JSON dictionary format (i.e. {"Command":"calc.exe"})`)
-
- if err := wmiCallCmd.MarkFlagRequired("class"); err != nil {
- panic(err)
- }
- if err := wmiCallCmd.MarkFlagRequired("method"); err != nil {
- panic(err)
- }
+ wmiCallCmd.Flags().StringVarP(&wmiCall.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
+ wmiCallCmd.Flags().StringVarP(&wmiCall.Class, "class", "C", "", `WMI class to instantiate (i.e. "Win32_Process")`)
+ wmiCallCmd.Flags().StringVarP(&wmiCall.Method, "method", "m", "", `WMI Method to call (i.e. "Create")`)
+ wmiCallCmd.Flags().StringVarP(&wmiArguments, "args", "A", "{}", `WMI Method argument(s) in JSON dictionary format (i.e. {"Command":"calc.exe"})`)
+
+ if err := wmiCallCmd.MarkFlagRequired("class"); err != nil {
+ panic(err)
+ }
+ if err := wmiCallCmd.MarkFlagRequired("method"); err != nil {
+ panic(err)
+ }
}
func wmiProcCmdInit() {
- wmiProcCmd.Flags().StringVarP(&wmiProc.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
- wmiProcCmd.Flags().StringVarP(&wmiProc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
+ wmiProcCmd.Flags().StringVarP(&wmiProc.Resource, "namespace", "n", "//./root/cimv2", "WMI namespace")
+ wmiProcCmd.Flags().StringVarP(&wmiProc.WorkingDirectory, "directory", "d", `C:\`, "Working directory")
- registerProcessExecutionArgs(wmiProcCmd)
- registerExecutionOutputArgs(wmiProcCmd)
+ registerProcessExecutionArgs(wmiProcCmd)
+ registerExecutionOutputArgs(wmiProcCmd)
}
var (
- wmiCall = wmiexec.WmiCall{}
- wmiProc = wmiexec.WmiProc{}
-
- wmiArguments string
-
- wmiCmd = &cobra.Command{
- Use: "wmi",
- Short: "Establish execution via Windows Management Instrumentation Remote Protocol (MS-WMI)",
- Args: cobra.NoArgs,
- }
-
- wmiCallCmd = &cobra.Command{
- Use: "call",
- Short: "Execute specified WMI method",
- Long: `Description:
+ wmiCall = wmiexec.WmiCall{}
+ wmiProc = wmiexec.WmiProc{}
+
+ wmiArguments string
+
+ wmiCmd = &cobra.Command{
+ Use: "wmi",
+ Short: "Execute with Windows Management Instrumentation (MS-WMI)",
+ GroupID: "module",
+ Args: cobra.NoArgs,
+ }
+
+ wmiCallCmd = &cobra.Command{
+ Use: "call",
+ Short: "Execute specified WMI method",
+ Long: `Description:
The call method creates an instance of the specified WMI class (-c),
then calls the provided method (-m) with the provided arguments (-A).
References:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-classes
`,
- Args: args(argsRpcClient("host"), wmiCallArgs),
-
- Run: func(cmd *cobra.Command, args []string) {
- var err error
-
- ctx := gssapi.NewSecurityContext(context.Background())
-
- ctx = log.With().
- Str("module", "wmi").
- Str("method", "call").
- Logger().
- WithContext(ctx)
-
- 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 = wmiCall.Init(ctx); err != nil {
- log.Error().Err(err).Msg("Module initialization failed")
- returnCode = 2
- return
- }
-
- out, err := wmiCall.Call(ctx)
- if err != nil {
- log.Error().Err(err).Msg("Call failed")
- returnCode = 4
- return
- }
- fmt.Println(string(out))
- },
- }
-
- wmiProcCmd = &cobra.Command{
- Use: "proc",
- Short: "Start a Windows process",
- Long: `Description:
+ Args: args(argsRpcClient("host"), wmiCallArgs),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ var err error
+
+ ctx := gssapi.NewSecurityContext(context.Background())
+
+ ctx = log.With().
+ Str("module", "wmi").
+ Str("method", "call").
+ Logger().
+ WithContext(ctx)
+
+ 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 = wmiCall.Init(ctx); err != nil {
+ log.Error().Err(err).Msg("Module initialization failed")
+ returnCode = 2
+ return
+ }
+
+ out, err := wmiCall.Call(ctx)
+ if err != nil {
+ log.Error().Err(err).Msg("Call failed")
+ returnCode = 4
+ return
+ }
+ fmt.Println(string(out))
+ },
+ }
+
+ wmiProcCmd = &cobra.Command{
+ Use: "proc",
+ Short: "Start a Windows process",
+ Long: `Description:
The proc method creates an instance of the Win32_Process WMI class, then
calls the Win32_Process.Create method with the provided command (-c),
and optional working directory (-d).
@@ -119,23 +120,23 @@ References:
References:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process
`,
- Args: args(
- argsOutput("smb"),
- argsRpcClient("host"),
- ),
-
- Run: func(cmd *cobra.Command, args []string) {
- wmiProc.Client = &rpcClient
- wmiProc.IO = exec
-
- ctx := log.With().
- Str("module", "wmi").
- Str("method", "proc").
- Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
-
- if err := goexec.ExecuteCleanMethod(ctx, &wmiProc, &exec); err != nil {
- log.Fatal().Err(err).Msg("Operation failed")
- }
- },
- }
+ Args: args(
+ argsOutput("smb"),
+ argsRpcClient("host"),
+ ),
+
+ Run: func(cmd *cobra.Command, args []string) {
+ wmiProc.Client = &rpcClient
+ wmiProc.IO = exec
+
+ ctx := log.With().
+ Str("module", "wmi").
+ Str("method", "proc").
+ Logger().WithContext(gssapi.NewSecurityContext(context.Background()))
+
+ if err := goexec.ExecuteCleanMethod(ctx, &wmiProc, &exec); err != nil {
+ log.Fatal().Err(err).Msg("Operation failed")
+ }
+ },
+ }
)
diff --git a/go.mod b/go.mod
index 7224fc0..8fb2c88 100644
--- a/go.mod
+++ b/go.mod
@@ -6,10 +6,12 @@ require (
github.com/RedTeamPentesting/adauth v0.2.0
github.com/google/uuid v1.6.0
github.com/oiweiwei/go-msrpc v1.2.5
+ github.com/oiweiwei/go-smb2.fork v1.0.0
github.com/rs/zerolog v1.34.0
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
golang.org/x/net v0.39.0
+ golang.org/x/term v0.31.0
)
require (
@@ -25,7 +27,6 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/oiweiwei/go-smb2.fork v1.0.0 // indirect
github.com/oiweiwei/gokrb5.fork/v9 v9.0.2 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/sys v0.32.0 // indirect
diff --git a/go.sum b/go.sum
index d611052..192629d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-github.com/RedTeamPentesting/adauth v0.1.1-0.20250304075117-acd47d454877 h1:n5V0EER+EvvmUZitR5zGFUMyoIHnI12SWFMciI7kh70=
-github.com/RedTeamPentesting/adauth v0.1.1-0.20250304075117-acd47d454877/go.mod h1:iHf/fY7CueB7qLHZ5YgTZXvrVCSLJy4+tAifOSNLAFQ=
github.com/RedTeamPentesting/adauth v0.2.0 h1:pNb4xcEd/oG/JY8aXkBm8Y0veVaUA/CsKFhgEgNCPik=
github.com/RedTeamPentesting/adauth v0.2.0/go.mod h1:AhWZEgl98YkKEta6kXTOSocQh2SbJJZg4nKqF+uY4bc=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -44,8 +42,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/oiweiwei/go-msrpc v1.2.4 h1:edFTNHkXqH/cssj0MDf1eRjW8xavdFNN2OrlteC3dRk=
-github.com/oiweiwei/go-msrpc v1.2.4/go.mod h1:ev+Bg4HdktdaLvwQ2RcwTlgvx7boe+fskcdUlesepdM=
github.com/oiweiwei/go-msrpc v1.2.5 h1:nIWoU7MWLk5l8vb0pgQ+D67GjDRPC4ybiR+OJtgDWdk=
github.com/oiweiwei/go-msrpc v1.2.5/go.mod h1:WoWRPfm90vRNZDJCwOiUXy39vjyQMAFrFj0zkWTThwY=
github.com/oiweiwei/go-smb2.fork v1.0.0 h1:xHq/eYPM8hQEO/nwCez8YwHWHC8mlcsgw/Neu52fPN4=
@@ -55,10 +51,7 @@ github.com/oiweiwei/gokrb5.fork/v9 v9.0.2/go.mod h1:KEnkAYUYqZ5VwzxLFbv3JHlRhCvd
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
-github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
-github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -79,8 +72,6 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
-golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -90,10 +81,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
-golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
-golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
-golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -107,19 +94,17 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
+golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/pkg/goexec/dcom/mmc.go b/pkg/goexec/dcom/mmc.go
index ecb3a74..993d1bb 100644
--- a/pkg/goexec/dcom/mmc.go
+++ b/pkg/goexec/dcom/mmc.go
@@ -1,51 +1,51 @@
package dcomexec
import (
- "context"
- "fmt"
- "github.com/FalconOpsLLC/goexec/pkg/goexec"
- "github.com/rs/zerolog"
+ "context"
+ "fmt"
+ "github.com/FalconOpsLLC/goexec/pkg/goexec"
+ "github.com/rs/zerolog"
)
const (
- MethodMmc = "MMC" // MMC20.Application::Document.ActiveView.ExecuteShellCommand
+ MethodMmc = "MMC" // MMC20.Application::Document.ActiveView.ExecuteShellCommand
)
type DcomMmc struct {
- Dcom
+ Dcom
- IO goexec.ExecutionIO
+ IO goexec.ExecutionIO
- WorkingDirectory string
- WindowState string
+ WorkingDirectory string
+ WindowState string
}
// Execute will perform command execution via the MMC20.Application DCOM object.
func (m *DcomMmc) Execute(ctx context.Context, execIO *goexec.ExecutionIO) (err error) {
- log := zerolog.Ctx(ctx).With().
- Str("module", ModuleName).
- Str("method", MethodMmc).
- Logger()
-
- method := "Document.ActiveView.ExecuteShellCommand"
-
- cmdline := execIO.CommandLine()
- proc := cmdline[0]
- args := cmdline[1]
-
- // Arguments must be passed in reverse order
- if _, err := callComMethod(ctx,
- m.dispatchClient,
- method,
- stringToVariant(m.WindowState),
- stringToVariant(args),
- stringToVariant(m.WorkingDirectory),
- stringToVariant(proc)); err != nil {
-
- log.Error().Err(err).Msg("Failed to call method")
- return fmt.Errorf("call %q: %w", method, err)
- }
- log.Info().Msg("Method call successful")
- return
+ log := zerolog.Ctx(ctx).With().
+ Str("module", ModuleName).
+ Str("method", MethodMmc).
+ Logger()
+
+ method := "Document.ActiveView.ExecuteShellCommand"
+
+ cmdline := execIO.CommandLine()
+ proc := cmdline[0]
+ args := cmdline[1]
+
+ // Arguments must be passed in reverse order
+ if _, err := callComMethod(ctx,
+ m.dispatchClient,
+ method,
+ stringToVariant(m.WindowState),
+ stringToVariant(args),
+ stringToVariant(m.WorkingDirectory),
+ stringToVariant(proc)); err != nil {
+
+ log.Error().Err(err).Msg("Failed to call method")
+ return fmt.Errorf("call %q: %w", method, err)
+ }
+ log.Info().Msg("Method call successful")
+ return
}
diff --git a/pkg/goexec/dcom/module.go b/pkg/goexec/dcom/module.go
index 71e4f6e..40804c3 100644
--- a/pkg/goexec/dcom/module.go
+++ b/pkg/goexec/dcom/module.go
@@ -1,120 +1,131 @@
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/msrpc/dcom"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/iremotescmactivator/v0"
- "github.com/oiweiwei/go-msrpc/msrpc/dcom/oaut/idispatch/v0"
- "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"
)
const (
- ModuleName = "DCOM"
+ ModuleName = "DCOM"
)
type Dcom struct {
- goexec.Cleaner
+ goexec.Cleaner
- Client *dce.Client
+ 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.AddCleaner(m.Client.Close)
- }
- return
+ if err = m.Client.Connect(ctx); err == nil {
+ m.AddCleaner(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")
- }
-
- opts := []dcerpc.Option{
- dcerpc.WithSign(),
- }
-
- inst := &dcom.InstantiationInfoData{
- ClassID: &MmcClsid,
- 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")
- }
-
- opts = append(opts, si.RemoteReply.OXIDBindings.EndpointsByProtocol("ncacn_ip_tcp")...)
-
- 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")
+ }
+
+ opts = append(opts, si.RemoteReply.OXIDBindings.EndpointsByProtocol("ncacn_ip_tcp")...)
+
+ 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
}