Skip to content

Commit 4a46d46

Browse files
committed
feat: add fragmented bind/alter-context auth support
1 parent 60ff623 commit 4a46d46

File tree

4 files changed

+101
-12
lines changed

4 files changed

+101
-12
lines changed

dcerpc/packet.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ type Packet struct {
3838
start, end int
3939
}
4040

41+
func (p *Packet) Unset(flag PacketFlag) {
42+
p.Header.PacketFlags &^= flag
43+
}
44+
45+
func (p *Packet) Set(flag PacketFlag) {
46+
p.Header.PacketFlags |= flag
47+
}
48+
49+
func (p *Packet) PDUHeaderSize() int {
50+
if sizer := p.PDU.(interface{ Size() int }); sizer != nil {
51+
return HeaderSize + sizer.Size() + MaxPad + SecurityTrailerSize
52+
}
53+
return 0
54+
}
55+
4156
func (p *Packet) IsLastFrag() bool {
4257
return p.Header.PacketFlags&PacketFlagLastFrag != 0
4358
}
@@ -332,7 +347,7 @@ func (c *transport) EncodePacket(ctx context.Context, pkt *Packet, raw []byte) e
332347
pkt.raw, pkt.end = raw, len(raw)
333348

334349
// set packet rpc version.
335-
pkt.Header.RPCVersion, pkt.Header.RPCVersionMinor = 5, 0
350+
pkt.Header.RPCVersion = 5
336351
// set packet drep.
337352
pkt.Header.PacketDRep = c.settings.DataRepresentation
338353
// set packet type.
@@ -364,14 +379,20 @@ func (c *transport) EncodePacket(ctx context.Context, pkt *Packet, raw []byte) e
364379

365380
// adjust stub buffer to include security trailer.
366381
if pkt.Header.AuthLength > 0 {
367-
pkt.end -= MaxPad + SecurityTrailerSize + int(pkt.Header.AuthLength)
382+
sz := MaxPad + SecurityTrailerSize + int(pkt.Header.AuthLength)
383+
if pkt.end -= sz; pkt.end <= 0 {
384+
return fmt.Errorf("encode_packet: insufficient buffer size for security trailer (%d bytes)", sz)
385+
}
368386
}
369387

370388
// XXX: verification is computed for every fragment, however it's being
371389
// written only for last fragment.
372390
verifyLen := pkt.VerificationTrailer.Size()
373391
if verifyLen > 0 {
374-
pkt.end -= VerificationTrailerMaxPad + verifyLen /* VerificationMaxPad */
392+
sz := VerificationTrailerMaxPad + verifyLen /* VerificationMaxPad */
393+
if pkt.end -= sz; pkt.end <= 0 {
394+
return fmt.Errorf("encode_packet: insufficient buffer size for verification trailer (%d bytes)", verifyLen)
395+
}
375396
}
376397

377398
w := c.Codec(raw, pkt.Header.PacketDRep)

dcerpc/pdu.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ type Auth3 struct {
7070
Pad [4]byte
7171
}
7272

73+
func (pdu *Auth3) Size() int {
74+
return 4
75+
}
76+
7377
func (pdu *Auth3) MarshalZerologObject(e *zerolog.Event) {}
7478

7579
// marshal function ...
@@ -101,6 +105,14 @@ type AlterContext struct {
101105
ContextList []*Context
102106
}
103107

108+
func (pdu *AlterContext) Size() int {
109+
size := 8 + 1
110+
for _, ctx := range pdu.ContextList {
111+
size += ctx.Size()
112+
}
113+
return size
114+
}
115+
104116
func (pdu *AlterContext) MarshalZerologObject(e *zerolog.Event) {}
105117

106118
func (pdu *AlterContext) WriteTo(ctx context.Context, w ndr.Writer) error {
@@ -201,6 +213,14 @@ type Bind struct {
201213
ContextList []*Context
202214
}
203215

216+
func (pdu *Bind) Size() int {
217+
size := 8 + 1
218+
for _, ctx := range pdu.ContextList {
219+
size += ctx.Size()
220+
}
221+
return size
222+
}
223+
204224
func (pdu *Bind) MarshalZerologObject(e *zerolog.Event) {}
205225

206226
func (pdu *Bind) WriteTo(ctx context.Context, w ndr.Writer) error {

dcerpc/transport.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,40 @@ func (c *transport) ExportSMBSecurity(o *Security) {
153153

154154
}
155155

156+
// writePacketFragmentedAuth writes the packet with fragmented authentication data.
157+
func (c *transport) writePacketFragmentedAuth(ctx context.Context, call Call, pkt *Packet) error {
158+
159+
authData, maxSize := pkt.AuthData, c.settings.MaxXmitFrag-pkt.PDUHeaderSize()
160+
161+
// https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm:
162+
//
163+
// If pfc_flags does not have PFC_LAST_FRAG set and rpc_vers_minor is 1,
164+
// then the PDU has fragmented auth_verifier data. The server will assemble
165+
// the data concatenating sequentially each auth_verifier field until a
166+
// PDU is sent with PFC_LAST_FRAG flag set. This completed buffer is then
167+
// used as auth_verifier data.
168+
169+
for {
170+
171+
if pkt.Set(PacketFlagLastFrag); len(authData) > maxSize {
172+
pkt.AuthData, authData = authData[:maxSize], authData[maxSize:]
173+
pkt.Header.RPCVersionMinor = 1
174+
pkt.Unset(PacketFlagLastFrag)
175+
}
176+
177+
// write bind pdu.
178+
if err := c.WritePacket(ctx, call, pkt); err != nil {
179+
return fmt.Errorf("alter context: write packet: %w", err)
180+
}
181+
182+
if pkt.Unset(PacketFlagFirstFrag); len(pkt.AuthData) <= maxSize {
183+
break
184+
}
185+
}
186+
187+
return nil
188+
}
189+
156190
// AlterContext function establishes new presentation or security (or both) context(s).
157191
func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, error) {
158192

@@ -193,11 +227,13 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
193227
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
194228
return nil, fmt.Errorf("alter context: init security: %w", err)
195229
}
196-
// write bind pdu.
197-
if err = c.WritePacket(ctx, call, pkt); err != nil {
198-
return nil, fmt.Errorf("alter context: write packet: %w", err)
230+
231+
// write alter-context pdu.
232+
if err := c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
233+
return nil, err
199234
}
200-
// read bind response (bind-ack, bind-nak).
235+
236+
// read alter-context response (alter-context-response).
201237
if pkt, err = c.ReadPacket(ctx, call, pkt); err != nil {
202238
return nil, fmt.Errorf("alter context: read packet: %w", err)
203239
}
@@ -243,14 +279,14 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
243279
// replace type with auth3.
244280
pkt.PDU = &Auth3{}
245281
// write auth3 pdu.
246-
if err = c.WritePacket(ctx, call, pkt); err != nil {
282+
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
247283
return nil, fmt.Errorf("alter context: auth3: write packet: %w", err)
248284
}
249285
// no response is assumed.
250286
break
251287
}
252288
// write alter_context request.
253-
if err = c.WritePacket(ctx, call, pkt); err != nil {
289+
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
254290
return nil, fmt.Errorf("alter context: write packet: %w", err)
255291
}
256292
// read alter_context response.
@@ -385,7 +421,7 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
385421
return nil, fmt.Errorf("bind: %w", err)
386422
}
387423
// write bind pdu.
388-
if err = c.WritePacket(ctx, call, pkt); err != nil {
424+
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
389425
return nil, fmt.Errorf("bind: write packet: %w", err)
390426
}
391427
// read bind response (bind-ack, bind-nak).
@@ -463,14 +499,14 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
463499
// replace type with auth3.
464500
pkt.PDU = &Auth3{}
465501
// write auth3 pdu.
466-
if err = c.WritePacket(ctx, call, pkt); err != nil {
502+
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
467503
return nil, fmt.Errorf("bind: alter context: auth3: write packet: %w", err)
468504
}
469505
// no response is assumed.
470506
break
471507
}
472508
// write alter_context request.
473-
if err = c.WritePacket(ctx, call, pkt); err != nil {
509+
if err = c.writePacketFragmentedAuth(ctx, call, pkt); err != nil {
474510
return nil, fmt.Errorf("bind: alter context: write packet: %w", err)
475511
}
476512
// read alter_context response.

dcerpc/types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ type SyntaxID struct {
1414
IfVersionMinor uint16
1515
}
1616

17+
func (v *SyntaxID) Size() int {
18+
return 16 + 2 + 2
19+
}
20+
1721
func (v *SyntaxID) Is(other *SyntaxID) bool {
1822
if v == nil || other == nil {
1923
return false
@@ -85,6 +89,14 @@ type Context struct {
8589
TransferSyntaxes []*SyntaxID
8690
}
8791

92+
func (c *Context) Size() int {
93+
size := 4 + c.AbstractSyntax.Size()
94+
for i := range c.TransferSyntaxes {
95+
size += c.TransferSyntaxes[i].Size()
96+
}
97+
return size
98+
}
99+
88100
// marshal function ...
89101
func (c *Context) WriteTo(ctx context.Context, w ndr.Writer) error {
90102
w.WriteData(c.ContextID)

0 commit comments

Comments
 (0)