aboutsummaryrefslogtreecommitdiff
path: root/internal/client/dce/dce.go
blob: f58123b18aed93a2218e24bcd2c2e371df433aea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package dce

import (
  "context"
  "errors"
  "fmt"
  "github.com/RedTeamPentesting/adauth"
  "github.com/RedTeamPentesting/adauth/dcerpcauth"
  "github.com/oiweiwei/go-msrpc/dcerpc"
  "github.com/oiweiwei/go-msrpc/midl/uuid"
  "github.com/oiweiwei/go-msrpc/msrpc/epm/epm/v3"
  "github.com/oiweiwei/go-msrpc/ssp/gssapi"
  "github.com/rs/zerolog"
)

type ConnectionMethodDCEConfig struct {
  NoEpm      bool // NoEpm disables EPM
  EpmAuto    bool // EpmAuto will find any suitable endpoint, without any filter
  Insecure   bool
  NoSign     bool
  Endpoint   *dcerpc.StringBinding // Endpoint is the explicit endpoint passed to dcerpc.WithEndpoint for use without EPM
  EpmFilter  *dcerpc.StringBinding // EpmFilter is the rough filter used to pick an EPM endpoint
  DceOptions []dcerpc.Option       // DceOptions are the options passed to dcerpc.Dial
  EpmOptions []dcerpc.Option       // EpmOptions are the options passed to epm.EndpointMapper
}

func (cfg *ConnectionMethodDCEConfig) GetDce(ctx context.Context, cred *adauth.Credential, target *adauth.Target, endpoint, object string, opts ...dcerpc.Option) (cc dcerpc.Conn, err error) {
  dceOpts := append(opts, cfg.DceOptions...)
  epmOpts := append(opts, cfg.EpmOptions...)

  log := zerolog.Ctx(ctx).With().
    Str("client", "DCERPC").Logger()

  // Mandatory logging
  dceOpts = append(dceOpts, dcerpc.WithLogger(log))
  epmOpts = append(epmOpts, dcerpc.WithLogger(log))

  ctx = gssapi.NewSecurityContext(ctx)
  auth, err := dcerpcauth.AuthenticationOptions(ctx, cred, target, &dcerpcauth.Options{})
  if err != nil {
    log.Error().Err(err).Msg("Failed to parse authentication options")
    return nil, fmt.Errorf("parse auth options: %w", err)
  }
  addr := target.AddressWithoutPort()
  log = log.With().Str("address", addr).Logger()

  if object != "" {
    if id, err := uuid.Parse(object); err != nil {
      log.Error().Err(err).Msg("Failed to parse input object UUID")
    } else {
      dceOpts = append(dceOpts, dcerpc.WithObjectUUID(id))
    }
  }
  if cfg.Endpoint != nil {
    dceOpts = append(dceOpts, dcerpc.WithEndpoint(cfg.Endpoint.String()))
    log.Debug().Str("binding", cfg.Endpoint.String()).Msg("Using endpoint")

  } else if !cfg.NoEpm {
    dceOpts = append(dceOpts, epm.EndpointMapper(ctx, addr, append(epmOpts, auth...)...))
    log.Debug().Msg("Using endpoint mapper")

    if cfg.EpmFilter != nil {
      dceOpts = append(dceOpts, dcerpc.WithEndpoint(cfg.EpmFilter.String()))
      log.Debug().Str("filter", cfg.EpmFilter.String()).Msg("Using endpoint filter")
    }
  } else if endpoint != "" {
    dceOpts = append(dceOpts, dcerpc.WithEndpoint(endpoint))
    log.Debug().Str("endpoint", endpoint).Msg("Using default endpoint")

  } else {
    log.Err(err).Msg("Invalid DCE connection options")
    return nil, errors.New("get DCE: invalid connection options")
  }

  return dcerpc.Dial(ctx, target.AddressWithoutPort(), append(dceOpts, auth...)...)
}