diff options
author | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-22 15:49:46 -0500 |
---|---|---|
committer | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-22 15:49:46 -0500 |
commit | ccef329bcdb90809cfd5b99ae646c397ee3c13ae (patch) | |
tree | b44c7581f20f21374f5ccfe731be65ea87160031 | |
parent | b76db931dc73df38476940d44c7f50e06f298152 (diff) | |
download | goexec-ccef329bcdb90809cfd5b99ae646c397ee3c13ae.tar.gz goexec-ccef329bcdb90809cfd5b99ae646c397ee3c13ae.zip |
Fixed proxy w/ EPM, fixed TSCH with ncacn_np
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | cmd/args.go | 2 | ||||
-rw-r--r-- | pkg/goexec/dce/client.go | 131 | ||||
-rw-r--r-- | pkg/goexec/dce/options.go | 193 | ||||
-rw-r--r-- | pkg/goexec/tsch/module.go | 3 |
5 files changed, 165 insertions, 166 deletions
@@ -40,7 +40,7 @@ ## Bug Fixes - [X] Fix SMB transport for SCMR module - `rpc_s_cannot_support: The requested operation is not supported.` -- [ ] Fix proxy - EPM, SMB don't use the proxy dialer +- [X] Fix proxy - EPM doesn't use the proxy dialer - [ ] Fix SCMR `change` method so that dependencies field isn't permanently overwritten ## Lower Priority diff --git a/cmd/args.go b/cmd/args.go index 51b490f..9568395 100644 --- a/cmd/args.go +++ b/cmd/args.go @@ -46,7 +46,7 @@ func registerExecutionFlags(fs *pflag.FlagSet) { func registerExecutionOutputFlags(fs *pflag.FlagSet) { fs.StringVarP(&outputPath, "out", "o", "", `Fetch execution output to file or "-" for standard output`) fs.StringVarP(&outputMethod, "out-method", "m", "smb", "Method to fetch execution output") - fs.StringVar(&exec.Output.RemotePath, "out-remote", "", "Location to temporarily store output on remote filesystem") + //fs.StringVar(&exec.Output.RemotePath, "out-remote", "", "Location to temporarily store output on remote filesystem") fs.BoolVar(&exec.Output.NoDelete, "no-delete-out", false, "Preserve output file on remote filesystem") } diff --git a/pkg/goexec/dce/client.go b/pkg/goexec/dce/client.go index 18400f6..0918933 100644 --- a/pkg/goexec/dce/client.go +++ b/pkg/goexec/dce/client.go @@ -1,107 +1,110 @@ package dce import ( - "context" - "fmt" - "github.com/RedTeamPentesting/adauth/smbauth" - "github.com/oiweiwei/go-msrpc/dcerpc" - "github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3" - msrpcSMB2 "github.com/oiweiwei/go-msrpc/smb2" - "github.com/rs/zerolog" + "context" + "fmt" + "github.com/RedTeamPentesting/adauth/smbauth" + "github.com/oiweiwei/go-msrpc/dcerpc" + "github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3" + msrpcSMB2 "github.com/oiweiwei/go-msrpc/smb2" + "github.com/rs/zerolog" ) type Client struct { - Options + Options - conn dcerpc.Conn - hostname string + conn dcerpc.Conn + hostname string } func (c *Client) String() string { - return ClientName + return ClientName } func (c *Client) Reconnect(ctx context.Context, opts ...dcerpc.Option) (err error) { - c.DcerpcOptions = append(c.DcerpcOptions, opts...) + c.DcerpcOptions = append(c.DcerpcOptions, opts...) - return c.Connect(ctx) + return c.Connect(ctx) } func (c *Client) Dce() (dce dcerpc.Conn) { - return c.conn + return c.conn } func (c *Client) Logger(ctx context.Context) (log zerolog.Logger) { - return zerolog.Ctx(ctx).With(). - Str("client", c.String()).Logger() + return zerolog.Ctx(ctx).With(). + Str("client", c.String()).Logger() } func (c *Client) Connect(ctx context.Context) (err error) { - log := c.Logger(ctx) - ctx = log.WithContext(ctx) + log := c.Logger(ctx) + ctx = log.WithContext(ctx) - var do, eo []dcerpc.Option + var do, eo []dcerpc.Option - do = append(do, c.DcerpcOptions...) - do = append(do, c.authOptions...) + do = append(do, c.DcerpcOptions...) + do = append(do, c.authOptions...) - if c.Smb { - c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithInsecure()) + do = append(do, dcerpc.WithSeal()) - var so []msrpcSMB2.DialerOption + if c.Smb { + var so []msrpcSMB2.DialerOption - if !c.NoSign { - so = append(so, msrpcSMB2.WithSign()) - } - if !c.NoSeal { - so = append(so, msrpcSMB2.WithSeal()) - } + if !c.NoSign { + so = append(so, msrpcSMB2.WithSign()) + eo = append(eo, dcerpc.WithSign()) + } + if !c.NoSeal { + so = append(so, msrpcSMB2.WithSeal()) + eo = append(eo, dcerpc.WithSeal()) + } - if smbDialer, err := smbauth.Dialer(ctx, c.Credential, c.Target, &smbauth.Options{SMBOptions: so}); err != nil { - return fmt.Errorf("parse smb auth: %w", err) + if smbDialer, err := smbauth.Dialer(ctx, c.Credential, c.Target, &smbauth.Options{SMBOptions: so}); err != nil { + return fmt.Errorf("parse smb auth: %w", err) - } else { - do = append(do, dcerpc.WithSMBDialer(smbDialer)) - } - } else { - if !c.NoSign { - do = append(do, dcerpc.WithSign()) - eo = append(eo, dcerpc.WithSign()) - } - if !c.NoSeal { - do = append(do, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) - eo = append(eo, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) - } - } + } else { + do = append(do, dcerpc.WithSMBDialer(smbDialer)) + } + } else { - if !c.NoLog { - do = append(do, dcerpc.WithLogger(log)) - eo = append(eo, dcerpc.WithLogger(log)) - } + if !c.NoSign { + do = append(do, dcerpc.WithSign()) + eo = append(eo, dcerpc.WithSign()) + } + if !c.NoSeal { + do = append(do, dcerpc.WithSeal()) + eo = append(eo, dcerpc.WithSeal()) + } + } - if !c.NoEpm { - log.Debug().Msg("Using endpoint mapper") + if !c.NoLog { + do = append(do, dcerpc.WithLogger(log)) + eo = append(eo, dcerpc.WithLogger(log)) + } - eo = append(eo, c.epmOptions...) - eo = append(eo, c.authOptions...) + if !c.NoEpm { + log.Debug().Msg("Using endpoint mapper") - do = append(do, epm.EndpointMapper(ctx, c.Host, eo...)) - } + eo = append(eo, c.EpmOptions...) + eo = append(eo, c.authOptions...) - for _, e := range c.stringBindings { - do = append(do, dcerpc.WithEndpoint(e.String())) - } + do = append(do, epm.EndpointMapper(ctx, c.Host, eo...)) + } - if c.conn, err = dcerpc.Dial(ctx, c.Host, do...); err != nil { + for _, e := range c.stringBindings { + do = append(do, dcerpc.WithEndpoint(e.String())) + } - log.Error().Err(err).Msgf("Failed to connect to %s endpoint", c.String()) - return fmt.Errorf("dial %s: %w", c.String(), err) - } + if c.conn, err = dcerpc.Dial(ctx, c.Host, do...); err != nil { - return + log.Error().Err(err).Msgf("Failed to connect to %s endpoint", c.String()) + return fmt.Errorf("dial %s: %w", c.String(), err) + } + + return } func (c *Client) Close(ctx context.Context) (err error) { - return c.conn.Close(ctx) + return c.conn.Close(ctx) } diff --git a/pkg/goexec/dce/options.go b/pkg/goexec/dce/options.go index b0c2a2f..b554009 100644 --- a/pkg/goexec/dce/options.go +++ b/pkg/goexec/dce/options.go @@ -1,118 +1,113 @@ package dce import ( - "context" - "fmt" - "github.com/FalconOpsLLC/goexec/pkg/goexec" - "github.com/RedTeamPentesting/adauth/dcerpcauth" - "github.com/oiweiwei/go-msrpc/dcerpc" - "net" + "context" + "fmt" + "github.com/FalconOpsLLC/goexec/pkg/goexec" + "github.com/RedTeamPentesting/adauth/dcerpcauth" + "github.com/oiweiwei/go-msrpc/dcerpc" ) type Options struct { - goexec.ClientOptions - goexec.AuthOptions + goexec.ClientOptions + goexec.AuthOptions - // NoSign disables packet signing by omitting dcerpc.WithSign() - NoSign bool `json:"no_sign" yaml:"no_sign"` + // NoSign disables packet signing by omitting dcerpc.WithSign() + NoSign bool `json:"no_sign" yaml:"no_sign"` - // NoSeal disables packet stub encryption by omitting dcerpc.WithSeal() - NoSeal bool `json:"no_seal" yaml:"no_seal"` + // NoSeal disables packet stub encryption by omitting dcerpc.WithSeal() + NoSeal bool `json:"no_seal" yaml:"no_seal"` - // NoLog disables logging by omitting dcerpc.WithLogger(...) - NoLog bool `json:"no_log" yaml:"no_log"` + // NoLog disables logging by omitting dcerpc.WithLogger(...) + NoLog bool `json:"no_log" yaml:"no_log"` - // NoEpm disables DCE endpoint mapper communications - NoEpm bool `json:"no_epm" yaml:"no_epm"` + // NoEpm disables DCE endpoint mapper communications + NoEpm bool `json:"no_epm" yaml:"no_epm"` - // Endpoint stores the explicit DCE string binding to use - Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` + // Endpoint stores the explicit DCE string binding to use + Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` - // Filter stores the filter for returned endpoints from an endpoint mapper - Filter string `json:"filter,omitempty" yaml:"filter,omitempty"` + // Filter stores the filter for returned endpoints from an endpoint mapper + Filter string `json:"filter,omitempty" yaml:"filter,omitempty"` - // Smb enables SMB transport for DCE/RPC - Smb bool `json:"use_smb" yaml:"use_smb"` + // Smb enables SMB transport for DCE/RPC + Smb bool `json:"use_smb" yaml:"use_smb"` - netDialer goexec.Dialer - dialer dcerpc.Dialer - authOptions []dcerpc.Option - DcerpcOptions []dcerpc.Option - epmOptions []dcerpc.Option - stringBindings []*dcerpc.StringBinding + stringBindings []*dcerpc.StringBinding + dialer dcerpc.Dialer + authOptions []dcerpc.Option + DcerpcOptions []dcerpc.Option + EpmOptions []dcerpc.Option } func (c *Client) Parse(ctx context.Context) (err error) { - // Reset internals - { - c.netDialer = nil - c.dialer = nil - c.stringBindings = []*dcerpc.StringBinding{} - c.authOptions = []dcerpc.Option{} - c.DcerpcOptions = []dcerpc.Option{} - c.epmOptions = []dcerpc.Option{ - dcerpc.WithSign(), // Require signing for EPM - } - } - - if !c.NoSeal { - // Enable encryption - c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) - c.epmOptions = append(c.epmOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) - } - if !c.NoSign { - // Enable signing - c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSign()) - //c.epmOptions = append(c.epmOptions, dcerpc.WithSign()) - } - - // Parse DCERPC endpoint - if c.Endpoint != "" { - sb, err := dcerpc.ParseStringBinding(c.Endpoint) - if err != nil { - return err - } - if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe { - c.Smb = true - } - c.stringBindings = append(c.stringBindings, sb) - } - - // Parse EPM filter - if c.Filter != "" { - sb, err := dcerpc.ParseStringBinding(c.Filter) - if err != nil { - return err - } - if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe { - c.Smb = true - } - c.stringBindings = append(c.stringBindings, sb) - } - - if c.Proxy == "" { - c.netDialer = &net.Dialer{} // FUTURE: additional dial c - - } else { - // Parse proxy URL - d, err := goexec.ParseProxyURI(c.Proxy) - if err != nil { - return err - } - var ok bool - if c.dialer, ok = d.(dcerpc.Dialer); !ok { - return fmt.Errorf("cannot cast %T to dcerpc.Dialer", d) - } - c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithDialer(c.dialer)) - } - - // Parse authentication parameters - if c.authOptions, err = dcerpcauth.AuthenticationOptions(ctx, c.Credential, c.Target, &dcerpcauth.Options{}); err != nil { - return fmt.Errorf("parse auth c: %w", err) - } - - c.Host = c.Target.AddressWithoutPort() - - return + // Reset internals + { + c.dialer = nil + c.stringBindings = []*dcerpc.StringBinding{} + c.authOptions = []dcerpc.Option{} + c.DcerpcOptions = []dcerpc.Option{} + c.EpmOptions = []dcerpc.Option{ + dcerpc.WithSign(), // Require signing for EPM + } + } + + if !c.NoSeal { + // Enable encryption + c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) + c.EpmOptions = append(c.EpmOptions, dcerpc.WithSeal(), dcerpc.WithSecurityLevel(dcerpc.AuthLevelPktPrivacy)) + } + if !c.NoSign { + // Enable signing + c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithSign()) + //c.EpmOptions = append(c.EpmOptions, dcerpc.WithSign()) + } + + // Parse DCERPC endpoint + if c.Endpoint != "" { + sb, err := dcerpc.ParseStringBinding(c.Endpoint) + if err != nil { + return err + } + if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe { + c.Smb = true + } + c.stringBindings = append(c.stringBindings, sb) + } + + // Parse EPM filter + if c.Filter != "" { + sb, err := dcerpc.ParseStringBinding(c.Filter) + if err != nil { + return err + } + if sb.ProtocolSequence == dcerpc.ProtocolSequenceNamedPipe { + c.Smb = true + } + c.stringBindings = append(c.stringBindings, sb) + } + + if c.Proxy != "" { + // Parse proxy URL + d, err := goexec.ParseProxyURI(c.Proxy) + if err != nil { + return err + } + var ok bool + if c.dialer, ok = d.(dcerpc.Dialer); !ok { + return fmt.Errorf("cannot cast %T to dcerpc.Dialer", d) + } + c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithDialer(c.dialer)) + c.EpmOptions = append(c.EpmOptions, dcerpc.WithDialer(c.dialer)) + } + + // Parse authentication parameters + if c.authOptions, err = dcerpcauth.AuthenticationOptions(ctx, c.Credential, c.Target, &dcerpcauth.Options{}); err != nil { + return fmt.Errorf("parse auth c: %w", err) + } + + c.Host = c.Target.AddressWithoutPort() + + return } diff --git a/pkg/goexec/tsch/module.go b/pkg/goexec/tsch/module.go index 72acf9b..677856d 100644 --- a/pkg/goexec/tsch/module.go +++ b/pkg/goexec/tsch/module.go @@ -7,6 +7,7 @@ import ( "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" ) @@ -51,7 +52,7 @@ func (m *Tsch) Init(ctx context.Context) (err error) { } // Create ITaskSchedulerService Client - m.tsch, err = itaskschedulerservice.NewTaskSchedulerServiceClient(ctx, m.Client.Dce()) + m.tsch, err = itaskschedulerservice.NewTaskSchedulerServiceClient(ctx, m.Client.Dce(), dcerpc.WithSeal()) return } |