Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ type Config struct {
Protocol string `json:"protocol"`

// The transfer encoding to use (ndr20, ndr64)
TrasnferEncoding string `json:"transfer_encoding"`
TransferEncoding string `json:"transfer_encoding"`

// The transfer window size.
TransportXmitSize int `json:"transport_xmit_size"`

// The flag that indicates whether credentials and mechanisms should be
// included into connection options. If GlobalCredentials is true, then
Expand Down Expand Up @@ -203,7 +206,8 @@ func New() *Config {
cfg.Auth.KRB5.DisablePAFXFAST = true
cfg.Auth.KRB5.AnyServiceClassSPN = true

cfg.TrasnferEncoding = "ndr20"
cfg.TransferEncoding = "ndr20"
cfg.TransportXmitSize = dcerpc.DefaultXmitSize

return cfg
}
Expand Down Expand Up @@ -373,7 +377,7 @@ func (cfg *Config) ClientOptions(ctx context.Context) []dcerpc.Option {

options := []dcerpc.Option{}

switch cfg.TrasnferEncoding {
switch cfg.TransferEncoding {
case "ndr20":
options = append(options, dcerpc.WithNDR20())
case "ndr64":
Expand Down Expand Up @@ -513,6 +517,10 @@ func (cfg *Config) getDialOptions() []dcerpc.Option {
options = append(options, dcerpc.WithSMBDialer(smb2.NewDialer(dialer...)))
}

if cfg.TransportXmitSize > 0 {
options = append(options, dcerpc.WithFragmentSize(cfg.TransportXmitSize))
}

if !cfg.useGlobalCredentials {
if cfg.useMachineAccount {
for _, cred := range cfg.MachineAccountCredentials() {
Expand Down Expand Up @@ -733,9 +741,9 @@ func (cfg *Config) ParseServerAddr() error {
switch extra {
// transfer encoding.
case "ndr20":
cfg.TrasnferEncoding = "ndr20"
cfg.TransferEncoding = "ndr20"
case "ndr64":
cfg.TrasnferEncoding = "ndr64"
cfg.TransferEncoding = "ndr64"
// auth type keywords.
case "spnego":
cfg.Auth.SPNEGO = true
Expand Down Expand Up @@ -806,10 +814,14 @@ func (cfg *Config) Validate() error {
}
}

if err := ValidateTransferEncoding(cfg.TrasnferEncoding); err != nil {
if err := ValidateTransferEncoding(cfg.TransferEncoding); err != nil {
return err
}

if cfg.TransportXmitSize <= 1024 {
return fmt.Errorf("transport xmit size must be greater than 1024")
}

if err := ValidateAuthLevel(cfg.Auth.Level); err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion config/flag/command_line.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func BindFlags(c *config.Config, flagSet *flag.FlagSet) {

flagSet.DurationVar(&c.Timeout, "timeout", c.Timeout, "timeout")

flagSet.StringVar(&c.TrasnferEncoding, "transfer-encoding", c.TrasnferEncoding, "transfer encoding: ndr20, ndr64")
flagSet.StringVar(&c.TransferEncoding, "transfer-encoding", c.TransferEncoding, "transfer encoding: ndr20, ndr64")
flagSet.IntVar(&c.TransportXmitSize, "transport-xmit-size", c.TransportXmitSize, "transport xmit size")

flagSet.StringVar(&c.Credential.Password, "password", c.Credential.Password, "password to authenticate with")
flagSet.StringVar(&c.Credential.NTHash, "nthash", c.Credential.NTHash, "NT hash to authenticate with")
Expand Down
12 changes: 8 additions & 4 deletions dcerpc/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ type BufferedConn struct {
cur, total []byte
}

func (conn *BufferedConn) Resized(sz int) *BufferedConn {
if sz > len(conn.total) {
conn.total = make([]byte, sz)
func resizeBuffer(buf []byte, sz int) []byte {
if sz > len(buf) {
return make([]byte, sz)
}
conn.cur, conn.total = nil, conn.total[:sz]
return buf[:sz]
}

func (conn *BufferedConn) Resized(sz int) *BufferedConn {
conn.cur, conn.total = nil, resizeBuffer(conn.total, sz)
return conn
}

Expand Down
27 changes: 24 additions & 3 deletions dcerpc/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ type Packet struct {
start, end int
}

func (p *Packet) Unset(flag PacketFlag) {
p.Header.PacketFlags &^= flag
}

func (p *Packet) Set(flag PacketFlag) {
p.Header.PacketFlags |= flag
}

func (p *Packet) PDUHeaderSize() int {
if sizer := p.PDU.(interface{ Size() int }); sizer != nil {
return HeaderSize + sizer.Size() + MaxPad + SecurityTrailerSize
}
return 0
}

func (p *Packet) IsLastFrag() bool {
return p.Header.PacketFlags&PacketFlagLastFrag != 0
}
Expand Down Expand Up @@ -332,7 +347,7 @@ func (c *transport) EncodePacket(ctx context.Context, pkt *Packet, raw []byte) e
pkt.raw, pkt.end = raw, len(raw)

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

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

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

w := c.Codec(raw, pkt.Header.PacketDRep)
Expand Down
22 changes: 22 additions & 0 deletions dcerpc/pdu.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ type Auth3 struct {
Pad [4]byte
}

func (pdu *Auth3) Size() int {
return 4
}

func (pdu *Auth3) MarshalZerologObject(e *zerolog.Event) {}

// marshal function ...
Expand Down Expand Up @@ -101,6 +105,14 @@ type AlterContext struct {
ContextList []*Context
}

func (pdu *AlterContext) Size() int {
size := 8 + 4
for _, ctx := range pdu.ContextList {
size += ctx.Size()
}
return size
}

func (pdu *AlterContext) MarshalZerologObject(e *zerolog.Event) {}

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

func (pdu *Bind) Size() int {
size := 8 + 4
for _, ctx := range pdu.ContextList {
size += ctx.Size()
}
return size
}

func (pdu *Bind) MarshalZerologObject(e *zerolog.Event) {}

func (pdu *Bind) WriteTo(ctx context.Context, w ndr.Writer) error {
Expand Down Expand Up @@ -305,6 +325,8 @@ func (pdu *BindNak) Error() string {
return "bind: authentication type was not recognized"
case InvalidChecksum:
return "bind: invalid checksum"
case ProtocolVersionNotSupported:
return "bind: protocol version not supported"
default:
return "bind: unknown error"
}
Expand Down
32 changes: 21 additions & 11 deletions dcerpc/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ func (c *transport) ExportSMBSecurity(o *Security) {
o.SetAttribute(gssapi.AttributeSMBEffectiveSessionKey, pipe.SessionKey())
}
}

}

// AlterContext function establishes new presentation or security (or both) context(s).
Expand Down Expand Up @@ -193,11 +192,13 @@ func (c *transport) AlterContext(ctx context.Context, opts ...Option) (Conn, err
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
return nil, fmt.Errorf("alter context: init security: %w", err)
}
// write bind pdu.
if err = c.WritePacket(ctx, call, pkt); err != nil {
return nil, fmt.Errorf("alter context: write packet: %w", err)

// write alter-context pdu.
if err := c.WritePacket(ctx, call, pkt); err != nil {
return nil, err
}
// read bind response (bind-ack, bind-nak).

// read alter-context response (alter-context-response).
if pkt, err = c.ReadPacket(ctx, call, pkt); err != nil {
return nil, fmt.Errorf("alter context: read packet: %w", err)
}
Expand Down Expand Up @@ -384,6 +385,18 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
if pkt.AuthData, err = o.Security.Init(ctx, nil); err != nil {
return nil, fmt.Errorf("bind: %w", err)
}

// XXX: adjust max xmit frag size if auth data is too large.
if len(pkt.AuthData) > c.settings.MaxXmitFrag-pkt.PDUHeaderSize() {
c.logger.Warn().Int("auth_data_size", len(pkt.AuthData)).
Int("max_xmit_frag", c.settings.MaxXmitFrag).
Msg("adjusting transmit buffer size to fit auth data")
sz := len(pkt.AuthData) + pkt.PDUHeaderSize()
c.settings.MaxXmitFrag = sz
// reset buffered connector.
c.cc, c.tx, c.rx = c.cc.Resized(sz), resizeBuffer(c.tx, sz), resizeBuffer(c.rx, sz)
}

// write bind pdu.
if err = c.WritePacket(ctx, call, pkt); err != nil {
return nil, fmt.Errorf("bind: write packet: %w", err)
Expand All @@ -397,11 +410,6 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {

case *BindAck:

if c.settings.MaxRecvFrag != int(pdu.MaxRecvFrag) {
// reset buffered connector.
c.cc = c.cc.Resized(int(pdu.MaxRecvFrag))
}

sz := c.settings.FragmentSize()

// save retrieved parameters.
Expand All @@ -414,7 +422,9 @@ func (c *transport) Bind(ctx context.Context, opts ...Option) (Conn, error) {
o.Group.SetID(int(pdu.AssocGroupID))

if sz != c.settings.FragmentSize() {
c.tx, c.rx = make([]byte, c.settings.FragmentSize()), make([]byte, c.settings.FragmentSize())
c.tx, c.rx = resizeBuffer(c.tx, c.settings.FragmentSize()), resizeBuffer(c.rx, c.settings.FragmentSize())
// reset buffered connector.
c.cc = c.cc.Resized(c.settings.FragmentSize())
}

// save negotiated header sign parameter.
Expand Down
13 changes: 13 additions & 0 deletions dcerpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ type SyntaxID struct {
IfVersionMinor uint16
}

func (v *SyntaxID) Size() int {
return 16 + 2 + 2
}

func (v *SyntaxID) Is(other *SyntaxID) bool {
if v == nil || other == nil {
return false
Expand Down Expand Up @@ -85,6 +89,14 @@ type Context struct {
TransferSyntaxes []*SyntaxID
}

func (c *Context) Size() int {
size := 4 + c.AbstractSyntax.Size()
for i := range c.TransferSyntaxes {
size += c.TransferSyntaxes[i].Size()
}
return size
}

// marshal function ...
func (c *Context) WriteTo(ctx context.Context, w ndr.Writer) error {
w.WriteData(c.ContextID)
Expand Down Expand Up @@ -140,6 +152,7 @@ const (
AbstractSyntaxNotSupported ProviderReason = 0x0001
ProposedTransferSyntaxesNotSupported ProviderReason = 0x0002
LocalLimitExceeded ProviderReason = 0x0003
ProtocolVersionNotSupported ProviderReason = 0x0004
AuthTypeNotRecognized ProviderReason = 0x0008
InvalidChecksum ProviderReason = 0x0009

Expand Down
Loading