diff options
author | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-22 15:09:05 -0500 |
---|---|---|
committer | Bryan McNulty <bryanmcnulty@protonmail.com> | 2025-04-22 15:09:05 -0500 |
commit | 4f30c57774947e9dd0664e60babadff9c3b1ebd9 (patch) | |
tree | 40de91ef9690d59f38e4ac1ddea5930ad48ab464 /pkg | |
parent | 9ba28f28184d7d8966a53abac2bec22dd581cde3 (diff) | |
download | goexec-4f30c57774947e9dd0664e60babadff9c3b1ebd9.tar.gz goexec-4f30c57774947e9dd0664e60babadff9c3b1ebd9.zip |
Fix ncacn_np transport with SCMR module
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/goexec/dce/client.go | 37 | ||||
-rw-r--r-- | pkg/goexec/scmr/module.go | 260 |
2 files changed, 156 insertions, 141 deletions
diff --git a/pkg/goexec/dce/client.go b/pkg/goexec/dce/client.go index 2fab71d..18400f6 100644 --- a/pkg/goexec/dce/client.go +++ b/pkg/goexec/dce/client.go @@ -6,6 +6,7 @@ import ( "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" ) @@ -16,10 +17,6 @@ type Client struct { hostname string } -func NewClient() *Client { - return new(Client) -} - func (c *Client) String() string { return ClientName } @@ -50,20 +47,32 @@ func (c *Client) Connect(ctx context.Context) (err error) { do = append(do, c.authOptions...) if c.Smb { - if smbDialer, err := smbauth.Dialer(ctx, c.Credential, c.Target, &smbauth.Options{}); err != nil { + c.DcerpcOptions = append(c.DcerpcOptions, dcerpc.WithInsecure()) + + var so []msrpcSMB2.DialerOption + + if !c.NoSign { + so = append(so, msrpcSMB2.WithSign()) + } + if !c.NoSeal { + so = append(so, msrpcSMB2.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) + } else { do = append(do, dcerpc.WithSMBDialer(smbDialer)) } - } - - 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 { + 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)) + } } if !c.NoLog { diff --git a/pkg/goexec/scmr/module.go b/pkg/goexec/scmr/module.go index 7b16247..708da23 100644 --- a/pkg/goexec/scmr/module.go +++ b/pkg/goexec/scmr/module.go @@ -1,186 +1,192 @@ package scmrexec import ( - "context" - "errors" - "fmt" - "github.com/FalconOpsLLC/goexec/internal/util" - "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/scmr/svcctl/v2" - "github.com/rs/zerolog" + "context" + "errors" + "fmt" + "github.com/FalconOpsLLC/goexec/internal/util" + "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/scmr/svcctl/v2" + "github.com/rs/zerolog" ) type Scmr struct { - goexec.Cleaner + goexec.Cleaner - Client *dce.Client - ctl svcctl.SvcctlClient - scm *svcctl.Handle + Client *dce.Client + ctl svcctl.SvcctlClient + scm *svcctl.Handle - hostname string + hostname string } const ( - ModuleName = "SCMR" + ModuleName = "SCMR" - DefaultEndpoint = "ncacn_np:[svcctl]" - ScmrUuid = "367ABB81-9844-35F1-AD32-98F038001003" + DefaultEndpoint = "ncacn_np:[svcctl]" + ScmrUuid = "367ABB81-9844-35F1-AD32-98F038001003" ) func (m *Scmr) 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 *Scmr) 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.hostname, err = m.Client.Target.Hostname(ctx) - if err != nil { - log.Debug().Err(err).Msg("Failed to determine target hostname") - } - if m.hostname == "" { - m.hostname = util.RandomHostname() - } - - m.ctl, err = svcctl.NewSvcctlClient(ctx, m.Client.Dce(), dcerpc.WithObjectUUID(uuid.MustParse(ScmrUuid))) - if err != nil { - log.Error().Err(err).Msg("Failed to initialize SVCCTL client") - return fmt.Errorf("create SVCCTL client: %w", err) - } - log.Info().Msg("Created SVCCTL client") - - resp, err := m.ctl.OpenSCMW(ctx, &svcctl.OpenSCMWRequest{ - MachineName: m.hostname, - DatabaseName: "ServicesActive\x00", - DesiredAccess: ServiceAllAccess, // TODO: Replace - }) - if err != nil { - log.Debug().Err(err).Msg("Failed to open SCM handle") - return fmt.Errorf("open SCM handle: %w", err) - } - log.Info().Msg("Opened SCM handle") - - m.scm = resp.SCM - - 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.hostname, err = m.Client.Target.Hostname(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to determine target hostname") + } + if m.hostname == "" { + m.hostname = util.RandomHostname() + } + + svcctlOpts := []dcerpc.Option{dcerpc.WithObjectUUID(uuid.MustParse(ScmrUuid))} + + if m.Client.Smb { + svcctlOpts = append(svcctlOpts, dcerpc.WithInsecure()) + } + + m.ctl, err = svcctl.NewSvcctlClient(ctx, m.Client.Dce(), svcctlOpts...) + if err != nil { + log.Error().Err(err).Msg("Failed to initialize SVCCTL client") + return fmt.Errorf("create SVCCTL client: %w", err) + } + log.Info().Msg("Created SVCCTL client") + + resp, err := m.ctl.OpenSCMW(ctx, &svcctl.OpenSCMWRequest{ + MachineName: m.hostname, + DatabaseName: "ServicesActive", + DesiredAccess: ServiceAllAccess, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to open SCM handle") + return fmt.Errorf("open SCM handle: %w", err) + } + log.Info().Msg("Opened SCM handle") + + m.scm = resp.SCM + + return } func (m *Scmr) Reconnect(ctx context.Context) (err error) { - if err = m.Client.Reconnect(ctx); err != nil { - return fmt.Errorf("reconnect: %w", err) - } - if err = m.Init(ctx); err != nil { - return fmt.Errorf("reconnect SCMR: %w", err) - } - return + if err = m.Client.Reconnect(ctx); err != nil { + return fmt.Errorf("reconnect: %w", err) + } + if err = m.Init(ctx); err != nil { + return fmt.Errorf("reconnect SCMR: %w", err) + } + return } // openService will a handle to the desired service func (m *Scmr) openService(ctx context.Context, name string) (svc *service, err error) { - log := zerolog.Ctx(ctx) + log := zerolog.Ctx(ctx) - resp, err := m.ctl.OpenServiceW(ctx, &svcctl.OpenServiceWRequest{ - ServiceManager: m.scm, - ServiceName: name, - DesiredAccess: ServiceAllAccess, // TODO: dynamic - }) - if err != nil { - log.Error().Err(err).Msg("Failed to open service handle") - return nil, fmt.Errorf("open service: %w", err) - } + resp, err := m.ctl.OpenServiceW(ctx, &svcctl.OpenServiceWRequest{ + ServiceManager: m.scm, + ServiceName: name, + DesiredAccess: ServiceAllAccess, // TODO: dynamic + }) + if err != nil { + log.Error().Err(err).Msg("Failed to open service handle") + return nil, fmt.Errorf("open service: %w", err) + } - log.Info().Msg("Opened service handle") + log.Info().Msg("Opened service handle") - svc = new(service) - svc.name = name - svc.handle = resp.Service + svc = new(service) + svc.name = name + svc.handle = resp.Service - return + return } func (m *Scmr) startService(ctx context.Context, svc *service) error { - log := zerolog.Ctx(ctx).With(). - Str("service", svc.name).Logger() + log := zerolog.Ctx(ctx).With(). + Str("service", svc.name).Logger() - sr, err := m.ctl.StartServiceW(ctx, &svcctl.StartServiceWRequest{Service: svc.handle}) + sr, err := m.ctl.StartServiceW(ctx, &svcctl.StartServiceWRequest{Service: svc.handle}) - if err != nil { + if err != nil { - if errors.Is(err, context.DeadlineExceeded) { // Check if execution timed out (execute "cmd.exe /c notepad" for test case) - log.Warn().Msg("Service execution deadline exceeded") - svc.handle = nil - return nil + if errors.Is(err, context.DeadlineExceeded) { // Check if execution timed out (execute "cmd.exe /c notepad" for test case) + log.Warn().Msg("Service execution deadline exceeded") + svc.handle = nil + return nil - } else if sr.Return == ErrorServiceRequestTimeout { - log.Info().Msg("Received request timeout. Execution was likely successful") - return nil - } + } else if sr.Return == ErrorServiceRequestTimeout { + log.Info().Msg("Received request timeout. Execution was likely successful") + return nil + } - log.Error().Err(err).Msg("Failed to start service") - return fmt.Errorf("start service: %w", err) - } - log.Info().Msg("Service started successfully") - return nil + log.Error().Err(err).Msg("Failed to start service") + return fmt.Errorf("start service: %w", err) + } + log.Info().Msg("Service started successfully") + return nil } func (m *Scmr) deleteService(ctx context.Context, svc *service) (err error) { - log := zerolog.Ctx(ctx).With(). - Str("service", svc.name).Logger() + log := zerolog.Ctx(ctx).With(). + Str("service", svc.name).Logger() - deleteResponse, err := m.ctl.DeleteService(ctx, &svcctl.DeleteServiceRequest{ - Service: svc.handle, - }) + deleteResponse, err := m.ctl.DeleteService(ctx, &svcctl.DeleteServiceRequest{ + Service: svc.handle, + }) - if err != nil { - log.Error().Err(err).Msg("Failed to delete service") - return fmt.Errorf("delete service: %w", err) - } + if err != nil { + log.Error().Err(err).Msg("Failed to delete service") + return fmt.Errorf("delete service: %w", err) + } - if deleteResponse.Return != 0 { - log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", deleteResponse.Return)).Msg("Failed to delete service") - return fmt.Errorf("delete service returned non-zero exit code: 0x%02x", deleteResponse.Return) - } + if deleteResponse.Return != 0 { + log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", deleteResponse.Return)).Msg("Failed to delete service") + return fmt.Errorf("delete service returned non-zero exit code: 0x%02x", deleteResponse.Return) + } - log.Info().Msg("Deleted service") - return + log.Info().Msg("Deleted service") + return } func (m *Scmr) closeService(ctx context.Context, svc *service) (err error) { - log := zerolog.Ctx(ctx).With(). - Str("service", svc.name).Logger() + log := zerolog.Ctx(ctx).With(). + Str("service", svc.name).Logger() - closResponse, err := m.ctl.CloseService(ctx, &svcctl.CloseServiceRequest{ - ServiceObject: svc.handle, - }) + closResponse, err := m.ctl.CloseService(ctx, &svcctl.CloseServiceRequest{ + ServiceObject: svc.handle, + }) - if err != nil { - log.Error().Err(err).Msg("Failed to close service handle") - return fmt.Errorf("close service: %w", err) - } + if err != nil { + log.Error().Err(err).Msg("Failed to close service handle") + return fmt.Errorf("close service: %w", err) + } - if closResponse.Return != 0 { - log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", closResponse.Return)).Msg("Failed to close service handle") - return fmt.Errorf("close service returned non-zero exit code: 0x%02x", closResponse.Return) - } + if closResponse.Return != 0 { + log.Error().Err(err).Str("code", fmt.Sprintf("0x%02x", closResponse.Return)).Msg("Failed to close service handle") + return fmt.Errorf("close service returned non-zero exit code: 0x%02x", closResponse.Return) + } - log.Info().Msg("Closed service handle") - return + log.Info().Msg("Closed service handle") + return } |