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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
package dcerpc
import (
"context"
"errors"
"fmt"
"github.com/bryanmcnulty/adauth"
"github.com/bryanmcnulty/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
}
|