aboutsummaryrefslogtreecommitdiff
path: root/internal/client/dcerpc/dcerpc.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/client/dcerpc/dcerpc.go')
-rw-r--r--internal/client/dcerpc/dcerpc.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/client/dcerpc/dcerpc.go b/internal/client/dcerpc/dcerpc.go
new file mode 100644
index 0000000..5c9a734
--- /dev/null
+++ b/internal/client/dcerpc/dcerpc.go
@@ -0,0 +1,106 @@
+package dcerpc
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "github.com/RedTeamPentesting/adauth"
+ "github.com/RedTeamPentesting/adauth/dcerpcauth"
+ "github.com/oiweiwei/go-msrpc/dcerpc"
+ "github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3"
+ "github.com/oiweiwei/go-msrpc/msrpc/scmr/svcctl/v2"
+ "github.com/oiweiwei/go-msrpc/smb2"
+ "github.com/oiweiwei/go-msrpc/ssp/gssapi"
+ "github.com/rs/zerolog"
+)
+
+const (
+ DceDefaultProto string = "ncacn_np"
+ DceDefaultPort uint16 = 445
+)
+
+type DCEClient struct {
+ Port uint16
+ Proto string
+
+ log zerolog.Logger
+ conn dcerpc.Conn
+ opts []dcerpc.Option
+ authOpts dcerpcauth.Options
+}
+
+func NewDCEClient(ctx context.Context, insecure bool, smbConfig *SmbConfig) (client *DCEClient) {
+ client = &DCEClient{
+ Port: DceDefaultPort,
+ Proto: DceDefaultProto,
+ log: zerolog.Ctx(ctx).With().Str("client", "DCE").Logger(),
+ authOpts: dcerpcauth.Options{},
+ }
+ client.opts = []dcerpc.Option{dcerpc.WithLogger(client.log)}
+ client.authOpts = dcerpcauth.Options{Debug: client.log.Trace().Msgf}
+
+ if smbConfig != nil {
+ if smbConfig.Port != 0 {
+ client.Port = smbConfig.Port
+ client.opts = append(client.opts, dcerpc.WithSMBPort(int(smbConfig.Port)))
+ }
+ }
+ if insecure {
+ client.log.Debug().Msg("Using insecure DCERPC connection")
+ client.opts = append(client.opts, dcerpc.WithInsecure())
+ } else {
+ client.log.Debug().Msg("Using secure DCERPC connection")
+ client.authOpts.SMBOptions = append(client.authOpts.SMBOptions, smb2.WithSeal())
+ }
+ return
+}
+
+func (client *DCEClient) OpenSvcctl(ctx context.Context) (ctl svcctl.SvcctlClient, err error) {
+ if client.conn == nil {
+ return nil, errors.New("DCE connection not open")
+ }
+ if ctl, err = svcctl.NewSvcctlClient(ctx, client.conn, dcerpc.WithInsecure()); err != nil {
+ client.log.Debug().Err(err).Msg("Failed to open Svcctl client")
+ }
+ return
+}
+
+func (client *DCEClient) DCE() dcerpc.Conn {
+ return client.conn
+}
+
+func (client *DCEClient) Connect(ctx context.Context, creds *adauth.Credential, target *adauth.Target, dialOpts ...dcerpc.Option) (err error) {
+ if creds != nil && target != nil {
+ authCtx := gssapi.NewSecurityContext(ctx)
+
+ binding := fmt.Sprintf(`%s:%s`, client.Proto, target.AddressWithoutPort())
+ mapper := epm.EndpointMapper(ctx, fmt.Sprintf("%s:%d", target.AddressWithoutPort(), client.Port), dcerpc.WithLogger(client.log))
+ dceOpts := []dcerpc.Option{dcerpc.WithLogger(client.log), dcerpc.WithSeal()}
+
+ if dceOpts, err = dcerpcauth.AuthenticationOptions(authCtx, creds, target, &client.authOpts); err == nil {
+ dceOpts = append(dceOpts, mapper)
+ dceOpts = append(dceOpts, client.opts...)
+ dceOpts = append(dceOpts, dialOpts...)
+
+ if client.conn, err = dcerpc.Dial(authCtx, binding, dceOpts...); err == nil {
+ client.log.Debug().Msg("Bind successful")
+ return nil
+ }
+ client.log.Debug().Err(err).Msg("DCERPC bind failed")
+ return errors.New("bind failed")
+ }
+ return errors.New("unable to parse DCE authentication options")
+ }
+ return errors.New("invalid arguments")
+}
+
+func (client *DCEClient) Close(ctx context.Context) (err error) {
+ if client.conn == nil {
+ client.log.Debug().Msg("Connection already closed")
+ } else if err = client.conn.Close(ctx); err == nil {
+ client.log.Debug().Msg("Connection closed successfully")
+ } else {
+ client.log.Error().Err(err).Msg("Failed to close connection")
+ }
+ return
+}