forked from codeexpress/respounder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsmb.go
420 lines (376 loc) · 10.1 KB
/
smb.go
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
package smb
import (
_ "errors"
"fmt"
"github.com/stacktitan/smb/gss"
"github.com/stacktitan/smb/ntlmssp"
"github.com/stacktitan/smb/smb/encoder"
)
const ProtocolSmb = "\xFFSMB"
const ProtocolSmb2 = "\xFESMB"
const StatusOk = 0x00000000
const StatusMoreProcessingRequired = 0xc0000016
const StatusInvalidParameter = 0xc000000d
const StatusLogonFailure = 0xc000006d
const StatusUserSessionDeleted = 0xc0000203
var StatusMap = map[uint32]string{
StatusOk: "OK",
StatusMoreProcessingRequired: "More Processing Required",
StatusInvalidParameter: "Invalid Parameter",
StatusLogonFailure: "Logon failed",
StatusUserSessionDeleted: "User session deleted",
}
const DialectSmb_2_0_2 = 0x0202
const DialectSmb_2_1 = 0x0210
const DialectSmb_3_0 = 0x0300
const DialectSmb_3_0_2 = 0x0302
const DialectSmb_3_1_1 = 0x0311
const DialectSmb2_ALL = 0x02FF
const (
CommandNegotiate uint16 = iota
CommandSessionSetup
CommandLogoff
CommandTreeConnect
CommandTreeDisconnect
CommandCreate
CommandClose
CommandFlush
CommandRead
CommandWrite
CommandLock
CommandIOCtl
CommandCancel
CommandEcho
CommandQueryDirectory
CommandChangeNotify
CommandQueryInfo
CommandSetInfo
CommandOplockBreak
)
const (
_ uint16 = iota
SecurityModeSigningEnabled
SecurityModeSigningRequired
)
const (
_ byte = iota
ShareTypeDisk
ShareTypePipe
ShareTypePrint
)
const (
ShareFlagManualCaching uint32 = 0x00000000
ShareFlagAutoCaching uint32 = 0x00000010
ShareFlagVDOCaching uint32 = 0x00000020
ShareFlagNoCaching uint32 = 0x00000030
ShareFlagDFS uint32 = 0x00000001
ShareFlagDFSRoot uint32 = 0x00000002
ShareFlagRestriceExclusiveOpens uint32 = 0x00000100
ShareFlagForceSharedDelete uint32 = 0x00000200
ShareFlagAllowNamespaceCaching uint32 = 0x00000400
ShareFlagAccessBasedDirectoryEnum uint32 = 0x00000800
ShareFlagForceLevelIIOplock uint32 = 0x00001000
ShareFlagEnableHashV1 uint32 = 0x00002000
ShareFlagEnableHashV2 uint32 = 0x00004000
ShareFlagEncryptData uint32 = 0x00008000
)
const (
ShareCapDFS uint32 = 0x00000008
ShareCapContinuousAvailability uint32 = 0x00000010
ShareCapScaleout uint32 = 0x00000020
ShareCapCluster uint32 = 0x00000040
ShareCapAsymmetric uint32 = 0x00000080
)
type Header struct {
ProtocolID []byte `smb:"fixed:4"`
StructureSize uint16
CreditCharge uint16
Status uint32
Command uint16
Credits uint16
Flags uint32
NextCommand uint32
MessageID uint64
Reserved uint32
TreeID uint32
SessionID uint64
Signature []byte `smb:"fixed:16"`
}
type NegotiateReq struct {
Header
StructureSize uint16
DialectCount uint16 `smb:"count:Dialects"`
SecurityMode uint16
Reserved uint16
Capabilities uint32
ClientGuid []byte `smb:"fixed:16"`
ClientStartTime uint64
Dialects []uint16
}
type NegotiateRes struct {
Header
StructureSize uint16
SecurityMode uint16
DialectRevision uint16
Reserved uint16
ServerGuid []byte `smb:"fixed:16"`
Capabilities uint32
MaxTransactSize uint32
MaxReadSize uint32
MaxWriteSize uint32
SystemTime uint64
ServerStartTime uint64
SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
Reserved2 uint32
SecurityBlob *gss.NegTokenInit
}
type SessionSetup1Req struct {
Header
StructureSize uint16
Flags byte
SecurityMode byte
Capabilities uint32
Channel uint32
SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
PreviousSessionID uint64
SecurityBlob *gss.NegTokenInit
}
type SessionSetup1Res struct {
Header
StructureSize uint16
Flags uint16
SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
SecurityBlob *gss.NegTokenResp
}
type SessionSetup2Req struct {
Header
StructureSize uint16
Flags byte
SecurityMode byte
Capabilities uint32
Channel uint32
SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
PreviousSessionID uint64
SecurityBlob *gss.NegTokenResp
}
type SessionSetup2Res struct {
Header
StructureSize uint16
Flags uint16
SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
SecurityBlob *gss.NegTokenResp
}
type TreeConnectReq struct {
Header
StructureSize uint16
Reserved uint16
PathOffset uint16 `smb:"offset:Path"`
PathLength uint16 `smb:"len:Path"`
Path []byte
}
type TreeConnectRes struct {
Header
StructureSize uint16
ShareType byte
Reserved byte
ShareFlags uint32
Capabilities uint32
MaximalAccess uint32
}
type TreeDisconnectReq struct {
Header
StructureSize uint16
Reserved uint16
}
type TreeDisconnectRes struct {
Header
StructureSize uint16
Reserved uint16
}
func newHeader() Header {
return Header{
ProtocolID: []byte(ProtocolSmb2),
StructureSize: 64,
CreditCharge: 0,
Status: 0,
Command: 0,
Credits: 0,
Flags: 0,
NextCommand: 0,
MessageID: 0,
Reserved: 0,
TreeID: 0,
SessionID: 0,
Signature: make([]byte, 16),
}
}
func (s *Session) NewNegotiateReq() NegotiateReq {
header := newHeader()
header.Command = CommandNegotiate
header.CreditCharge = 1
header.MessageID = s.messageID
dialects := []uint16{
uint16(DialectSmb_2_1),
}
return NegotiateReq{
Header: header,
StructureSize: 36,
DialectCount: uint16(len(dialects)),
SecurityMode: SecurityModeSigningEnabled,
Reserved: 0,
Capabilities: 0,
ClientGuid: make([]byte, 16),
ClientStartTime: 0,
Dialects: dialects,
}
}
func NewNegotiateRes() NegotiateRes {
return NegotiateRes{
Header: newHeader(),
StructureSize: 0,
SecurityMode: 0,
DialectRevision: 0,
Reserved: 0,
ServerGuid: make([]byte, 16),
Capabilities: 0,
MaxTransactSize: 0,
MaxReadSize: 0,
MaxWriteSize: 0,
SystemTime: 0,
ServerStartTime: 0,
SecurityBufferOffset: 0,
SecurityBufferLength: 0,
Reserved2: 0,
SecurityBlob: &gss.NegTokenInit{},
}
}
func (s *Session) NewSessionSetup1Req() (SessionSetup1Req, error) {
header := newHeader()
header.Command = CommandSessionSetup
header.CreditCharge = 1
header.MessageID = s.messageID
header.SessionID = s.sessionID
ntlmsspneg := ntlmssp.NewNegotiate(s.options.Domain, s.options.Workstation)
data, err := encoder.Marshal(ntlmsspneg)
if err != nil {
return SessionSetup1Req{}, err
}
//if s.sessionID != 0 {
// return SessionSetup1Req{}, errors.New("Bad session ID for session setup 1 message")
//}
// Initial session setup request
init, err := gss.NewNegTokenInit()
if err != nil {
return SessionSetup1Req{}, err
}
init.Data.MechToken = data
return SessionSetup1Req{
Header: header,
StructureSize: 25,
Flags: 0x00,
SecurityMode: byte(SecurityModeSigningEnabled),
Capabilities: 0,
Channel: 0,
SecurityBufferOffset: 88,
SecurityBufferLength: 0,
PreviousSessionID: 0,
SecurityBlob: &init,
}, nil
}
func NewSessionSetup1Res() (SessionSetup1Res, error) {
resp, err := gss.NewNegTokenResp()
if err != nil {
return SessionSetup1Res{}, err
}
ret := SessionSetup1Res{
Header: newHeader(),
SecurityBlob: &resp,
}
return ret, nil
}
func (s *Session) NewSessionSetup2Req() (SessionSetup2Req, error) {
header := newHeader()
header.Command = CommandSessionSetup
header.CreditCharge = 1
header.MessageID = s.messageID
header.SessionID = s.sessionID
ntlmsspneg := ntlmssp.NewNegotiate(s.options.Domain, s.options.Workstation)
data, err := encoder.Marshal(ntlmsspneg)
if err != nil {
return SessionSetup2Req{}, err
}
//if s.sessionID == 0 {
// return SessionSetup2Req{}, errors.New("Bad session ID for session setup 2 message")
//}
// Session setup request #2
resp, err := gss.NewNegTokenResp()
if err != nil {
return SessionSetup2Req{}, err
}
resp.ResponseToken = data
return SessionSetup2Req{
Header: header,
StructureSize: 25,
Flags: 0x00,
SecurityMode: byte(SecurityModeSigningEnabled),
Capabilities: 0,
Channel: 0,
SecurityBufferOffset: 88,
SecurityBufferLength: 0,
PreviousSessionID: 0,
SecurityBlob: &resp,
}, nil
}
func NewSessionSetup2Res() (SessionSetup2Res, error) {
resp, err := gss.NewNegTokenResp()
if err != nil {
return SessionSetup2Res{}, err
}
ret := SessionSetup2Res{
Header: newHeader(),
SecurityBlob: &resp,
}
return ret, nil
}
// NewTreeConnectReq creates a new TreeConnect message and accepts the share name
// as input.
func (s *Session) NewTreeConnectReq(name string) (TreeConnectReq, error) {
header := newHeader()
header.Command = CommandTreeConnect
header.CreditCharge = 1
header.MessageID = s.messageID
header.SessionID = s.sessionID
path := fmt.Sprintf("\\\\%s\\%s", s.options.Host, name)
return TreeConnectReq{
Header: header,
StructureSize: 9,
Reserved: 0,
PathOffset: 0,
PathLength: 0,
Path: encoder.ToUnicode(path),
}, nil
}
func NewTreeConnectRes() (TreeConnectRes, error) {
return TreeConnectRes{}, nil
}
func (s *Session) NewTreeDisconnectReq(treeId uint32) (TreeDisconnectReq, error) {
header := newHeader()
header.Command = CommandTreeDisconnect
header.CreditCharge = 1
header.MessageID = s.messageID
header.SessionID = s.sessionID
header.TreeID = treeId
return TreeDisconnectReq{
Header: header,
StructureSize: 4,
Reserved: 0,
}, nil
}
func NewTreeDisconnectRes() (TreeDisconnectRes, error) {
return TreeDisconnectRes{}, nil
}