Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/utils/telnetmini/smb.go
2843 views
1
package telnetmini
2
3
import (
4
"bytes"
5
"encoding/binary"
6
"fmt"
7
8
"github.com/Azure/go-ntlmssp"
9
)
10
11
// SMB constants for packet crafting
12
const (
13
// SMB Commands
14
SMB_COM_NEGOTIATE_PROTOCOL = 0x72
15
SMB_COM_SESSION_SETUP_ANDX = 0x73
16
SMB_COM_TREE_CONNECT_ANDX = 0x75
17
SMB_COM_NT_CREATE_ANDX = 0xA2
18
SMB_COM_READ_ANDX = 0x2E
19
SMB_COM_WRITE_ANDX = 0x2F
20
SMB_COM_CLOSE = 0x04
21
SMB_COM_TREE_DISCONNECT = 0x71
22
SMB_COM_LOGOFF_ANDX = 0x74
23
24
// SMB Flags
25
SMB_FLAGS_CANONICAL_PATHNAMES = 0x10
26
SMB_FLAGS_CASELESS_PATHNAMES = 0x08
27
SMB_FLAGS2_UNICODE_STRINGS = 0x8000
28
SMB_FLAGS2_ERRSTATUS = 0x4000
29
SMB_FLAGS2_READ_IF_EXECUTE = 0x2000
30
SMB_FLAGS2_32_BIT_ERRORS = 0x1000
31
SMB_FLAGS2_DFS = 0x0800
32
SMB_FLAGS2_EXTENDED_SECURITY = 0x0400
33
SMB_FLAGS2_REPARSE_PATH = 0x0200
34
SMB_FLAGS2_SMB_SECURITY_SIGNATURE = 0x0100
35
SMB_FLAGS2_SMB_SECURITY_SIGNATURE_REQUIRED = 0x0080
36
37
// SMB Security modes
38
SMB_SECURITY_SHARE = 0x00
39
SMB_SECURITY_USER = 0x01
40
SMB_SECURITY_DOMAIN = 0x02
41
42
// SMB Capabilities
43
SMB_CAP_EXTENDED_SECURITY = 0x80000000
44
SMB_CAP_COMPRESSED_DATA = 0x40000000
45
SMB_CAP_BULK_TRANSFER = 0x20000000
46
SMB_CAP_UNIX = 0x00800000
47
SMB_CAP_LARGE_READX = 0x00400000
48
SMB_CAP_LARGE_WRITEX = 0x00200000
49
SMB_CAP_INFOLEVEL_PASSTHRU = 0x00100000
50
SMB_CAP_DFS = 0x00080000
51
SMB_CAP_NT_FIND = 0x00040000
52
SMB_CAP_LOCK_AND_READ = 0x00020000
53
SMB_CAP_LEVEL_II_OPLOCKS = 0x00010000
54
SMB_CAP_STATUS32 = 0x00008000
55
SMB_CAP_RPC_REMOTE_APIS = 0x00004000
56
SMB_CAP_NT_SMBS = 0x00002000
57
58
// NTLM constants
59
NTLMSSP_NEGOTIATE_56 = 0x80000000
60
NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
61
NTLMSSP_NEGOTIATE_128 = 0x20000000
62
NTLMSSP_NEGOTIATE_VERSION = 0x02000000
63
NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
64
NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
65
NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
66
NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY = 0x00080000
67
NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
68
NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000
69
NTLMSSP_NEGOTIATE_NTLM = 0x00000200
70
NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
71
NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
72
NTLMSSP_NEGOTIATE_SEAL = 0x00000020
73
NTLMSSP_NEGOTIATE_SIGN = 0x00000010
74
NTLMSSP_REQUEST_TARGET = 0x00000004
75
NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
76
)
77
78
// SMBPacket represents a complete SMB packet
79
type SMBPacket struct {
80
NetBIOSHeader []byte
81
SMBHeader []byte
82
SMBData []byte
83
}
84
85
// SMBHeader represents the SMB header structure
86
type SMBHeader struct {
87
ProtocolID [4]byte // 0xFF, 'S', 'M', 'B'
88
Command byte
89
Status uint32
90
Flags byte
91
Flags2 uint16
92
PIDHigh uint16
93
Signature [8]byte
94
Reserved uint16
95
TreeID uint16
96
ProcessID uint16
97
UserID uint16
98
MultiplexID uint16
99
}
100
101
// CreateSMBPacket creates a complete SMB packet with NetBIOS header
102
func CreateSMBPacket(smbData []byte) *SMBPacket {
103
// Create NetBIOS header
104
netbiosHeader := make([]byte, 4)
105
netbiosHeader[0] = 0x00 // Message type (Session message)
106
netbiosHeader[1] = 0x00 // Padding
107
netbiosHeader[2] = 0x00 // Padding
108
109
// Calculate NetBIOS length (big-endian)
110
length := len(smbData)
111
netbiosHeader[3] = byte(length & 0xFF)
112
113
return &SMBPacket{
114
NetBIOSHeader: netbiosHeader,
115
SMBHeader: createSMBHeader(),
116
SMBData: smbData,
117
}
118
}
119
120
// createSMBHeader creates a standard SMB header
121
func createSMBHeader() []byte {
122
header := make([]byte, 32)
123
124
// Protocol ID: 0xFF, 'S', 'M', 'B'
125
header[0] = 0xFF
126
header[1] = 'S'
127
header[2] = 'M'
128
header[3] = 'B'
129
130
// Command (will be set by caller)
131
header[4] = 0x00
132
133
// Status (0 for requests)
134
binary.LittleEndian.PutUint32(header[5:9], 0)
135
136
// Flags
137
header[9] = SMB_FLAGS_CANONICAL_PATHNAMES
138
139
// Flags2
140
binary.LittleEndian.PutUint16(header[10:12], SMB_FLAGS2_UNICODE_STRINGS|SMB_FLAGS2_EXTENDED_SECURITY)
141
142
// PIDHigh, Signature, Reserved, TreeID, ProcessID, UserID, MultiplexID
143
// All set to 0 for new connections
144
binary.LittleEndian.PutUint16(header[12:14], 0) // PIDHigh
145
// Signature is 8 bytes of zeros
146
binary.LittleEndian.PutUint16(header[20:22], 0) // Reserved
147
binary.LittleEndian.PutUint16(header[22:24], 0) // TreeID
148
binary.LittleEndian.PutUint16(header[24:26], 0) // ProcessID
149
binary.LittleEndian.PutUint16(header[26:28], 0) // UserID
150
binary.LittleEndian.PutUint16(header[28:30], 0) // MultiplexID
151
152
return header
153
}
154
155
// CreateNegotiateProtocolPacket creates an SMB negotiate protocol packet
156
func CreateNegotiateProtocolPacket() []byte {
157
// Create SMB header
158
header := createSMBHeader()
159
header[4] = SMB_COM_NEGOTIATE_PROTOCOL
160
161
// Create negotiate protocol data
162
data := createNegotiateProtocolData()
163
164
// Combine header and data
165
packet := append(header, data...)
166
167
// Create complete packet with NetBIOS header
168
smbPacket := CreateSMBPacket(packet)
169
170
return smbPacket.Bytes()
171
}
172
173
// createNegotiateProtocolData creates the data portion of negotiate protocol packet
174
func createNegotiateProtocolData() []byte {
175
var buf bytes.Buffer
176
177
// Word count
178
_ = buf.WriteByte(0x00)
179
180
// Byte count
181
_ = buf.WriteByte(0x00)
182
183
// Dialect strings
184
dialects := []string{
185
"NT LM 0.12",
186
"SMB 2.002",
187
"SMB 2.???",
188
}
189
190
for _, dialect := range dialects {
191
_ = buf.WriteByte(byte(len(dialect)))
192
_, _ = buf.WriteString(dialect)
193
_ = buf.WriteByte(0x00)
194
}
195
196
// Update byte count
197
data := buf.Bytes()
198
data[1] = byte(len(data) - 2)
199
200
return data
201
}
202
203
// CreateSessionSetupPacket creates an SMB session setup packet
204
func CreateSessionSetupPacket(username, password, domain string, sessionKey uint64) []byte {
205
// Create SMB header
206
header := createSMBHeader()
207
header[4] = SMB_COM_SESSION_SETUP_ANDX
208
209
// Create session setup data
210
data := createSessionSetupData(username, password, domain, sessionKey)
211
212
// Combine header and data
213
packet := append(header, data...)
214
215
// Create complete packet with NetBIOS header
216
smbPacket := CreateSMBPacket(packet)
217
218
return smbPacket.Bytes()
219
}
220
221
// createSessionSetupData creates the data portion of session setup packet
222
func createSessionSetupData(username, password, domain string, sessionKey uint64) []byte {
223
var buf bytes.Buffer
224
225
// Word count
226
_ = buf.WriteByte(0x0D)
227
228
// AndXCommand (no chained command)
229
_ = buf.WriteByte(0xFF)
230
231
// AndXReserved
232
_ = buf.WriteByte(0x00)
233
234
// AndXOffset
235
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
236
237
// MaxBufferSize
238
_ = binary.Write(&buf, binary.LittleEndian, uint16(0xFFFF))
239
240
// MaxMpxCount
241
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x01))
242
243
// VcNumber
244
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x00))
245
246
// SessionKey
247
_ = binary.Write(&buf, binary.LittleEndian, uint32(sessionKey))
248
249
// CaseInsensitivePasswordLength
250
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(password)))
251
252
// CaseSensitivePasswordLength
253
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(password)))
254
255
// Reserved
256
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00))
257
258
// Capabilities
259
_ = binary.Write(&buf, binary.LittleEndian, uint32(SMB_CAP_EXTENDED_SECURITY|SMB_CAP_NT_SMBS))
260
261
// Byte count
262
_ = buf.WriteByte(0x00)
263
264
// CaseInsensitivePassword
265
_, _ = buf.WriteString(password)
266
267
// CaseSensitivePassword
268
_, _ = buf.WriteString(password)
269
270
// Account name
271
_, _ = buf.WriteString(username)
272
_ = buf.WriteByte(0x00)
273
274
// Primary domain
275
_, _ = buf.WriteString(domain)
276
_ = buf.WriteByte(0x00)
277
278
// Native OS
279
_, _ = buf.WriteString("Windows 2000 2195")
280
_ = buf.WriteByte(0x00)
281
282
// Native LAN Manager
283
_, _ = buf.WriteString("Windows 2000 5.0")
284
_ = buf.WriteByte(0x00)
285
286
// Update byte count
287
data := buf.Bytes()
288
data[len(data)-1] = byte(len(data) - 0x21) // 0x21 is the offset to the start of variable data
289
290
return data
291
}
292
293
// CreateTreeConnectPacket creates an SMB tree connect packet
294
func CreateTreeConnectPacket(shareName string, password string) []byte {
295
// Create SMB header
296
header := createSMBHeader()
297
header[4] = SMB_COM_TREE_CONNECT_ANDX
298
299
// Create tree connect data
300
data := createTreeConnectData(shareName, password)
301
302
// Combine header and data
303
packet := append(header, data...)
304
305
// Create complete packet with NetBIOS header
306
smbPacket := CreateSMBPacket(packet)
307
308
return smbPacket.Bytes()
309
}
310
311
// createTreeConnectData creates the data portion of tree connect packet
312
func createTreeConnectData(shareName, password string) []byte {
313
var buf bytes.Buffer
314
315
// Word count
316
_ = buf.WriteByte(0x04)
317
318
// AndXCommand (no chained command)
319
_ = buf.WriteByte(0xFF)
320
321
// AndXReserved
322
_ = buf.WriteByte(0x00)
323
324
// AndXOffset
325
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
326
327
// Flags
328
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x00))
329
330
// Password length
331
_ = buf.WriteByte(byte(len(password)))
332
333
// Byte count
334
_ = buf.WriteByte(0x00)
335
336
// Password
337
_, _ = buf.WriteString(password)
338
_ = buf.WriteByte(0x00)
339
340
// Tree
341
_, _ = buf.WriteString(shareName)
342
_ = buf.WriteByte(0x00)
343
344
// Service
345
_, _ = buf.WriteString("?????")
346
_ = buf.WriteByte(0x00)
347
348
// Update byte count
349
data := buf.Bytes()
350
data[7] = byte(len(data) - 0x0B) // 0x0B is the offset to the start of variable data
351
352
return data
353
}
354
355
// CreateNTCreatePacket creates an SMB NT create packet
356
func CreateNTCreatePacket(fileName string) []byte {
357
// Create SMB header
358
header := createSMBHeader()
359
header[4] = SMB_COM_NT_CREATE_ANDX
360
361
// Create NT create data
362
data := createNTCreateData(fileName)
363
364
// Combine header and data
365
packet := append(header, data...)
366
367
// Create complete packet with NetBIOS header
368
smbPacket := CreateSMBPacket(packet)
369
370
return smbPacket.Bytes()
371
}
372
373
// createNTCreateData creates the data portion of NT create packet
374
func createNTCreateData(fileName string) []byte {
375
var buf bytes.Buffer
376
377
// Word count
378
_ = buf.WriteByte(0x18)
379
380
// AndXCommand (no chained command)
381
_ = buf.WriteByte(0xFF)
382
383
// AndXReserved
384
_ = buf.WriteByte(0x00)
385
386
// AndXOffset
387
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
388
389
// Reserved
390
_ = buf.WriteByte(0x00)
391
392
// NameLength
393
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(fileName)))
394
395
// Flags
396
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
397
398
// RootDirectoryFID
399
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
400
401
// DesiredAccess
402
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
403
404
// AllocationSize
405
_ = binary.Write(&buf, binary.LittleEndian, uint64(0x0000000000000000))
406
407
// FileAttributes
408
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
409
410
// ShareAccess
411
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
412
413
// CreateDisposition
414
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000001)) // FILE_OPEN
415
416
// CreateOptions
417
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
418
419
// ImpersonationLevel
420
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000002)) // SecurityImpersonation
421
422
// SecurityFlags
423
_ = buf.WriteByte(0x00)
424
425
// Byte count
426
_ = buf.WriteByte(0x00)
427
428
// SecurityDescriptor
429
_ = buf.WriteByte(0x00)
430
431
// FileName
432
_, _ = buf.WriteString(fileName)
433
_ = buf.WriteByte(0x00)
434
435
// Update byte count
436
data := buf.Bytes()
437
data[0x3B] = byte(len(data) - 0x3C) // 0x3C is the offset to the start of variable data
438
439
return data
440
}
441
442
// Bytes returns the complete SMB packet as bytes
443
func (p *SMBPacket) Bytes() []byte {
444
var result bytes.Buffer
445
result.Write(p.NetBIOSHeader)
446
result.Write(p.SMBHeader)
447
result.Write(p.SMBData)
448
return result.Bytes()
449
}
450
451
// CreateNTLMNegotiatePacket creates an NTLM negotiate packet for SMB authentication
452
func CreateNTLMNegotiatePacket() []byte {
453
var buf bytes.Buffer
454
455
// NTLMSSP signature
456
_, _ = buf.WriteString("NTLMSSP")
457
_ = buf.WriteByte(0x00)
458
459
// Message type (1 = Negotiate)
460
_ = binary.Write(&buf, binary.LittleEndian, uint32(1))
461
462
// Negotiate flags
463
flags := uint32(NTLMSSP_NEGOTIATE_56 |
464
NTLMSSP_NEGOTIATE_128 |
465
NTLMSSP_NEGOTIATE_VERSION |
466
NTLMSSP_NEGOTIATE_TARGET_INFO |
467
NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY |
468
NTLMSSP_TARGET_TYPE_SERVER |
469
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
470
NTLMSSP_NEGOTIATE_NTLM |
471
NTLMSSP_NEGOTIATE_UNICODE)
472
_ = binary.Write(&buf, binary.LittleEndian, flags)
473
474
// Domain name fields (empty for negotiate)
475
_ = binary.Write(&buf, binary.LittleEndian, uint16(0)) // DomainNameLen
476
_ = binary.Write(&buf, binary.LittleEndian, uint16(0)) // DomainNameMaxLen
477
_ = binary.Write(&buf, binary.LittleEndian, uint32(0)) // DomainNameBufferOffset
478
479
// Workstation name fields (empty for negotiate)
480
_ = binary.Write(&buf, binary.LittleEndian, uint16(0)) // WorkstationNameLen
481
_ = binary.Write(&buf, binary.LittleEndian, uint16(0)) // WorkstationNameMaxLen
482
_ = binary.Write(&buf, binary.LittleEndian, uint32(0)) // WorkstationNameBufferOffset
483
484
// Version
485
_ = buf.WriteByte(0x05) // Major version
486
_ = buf.WriteByte(0x02) // Minor version
487
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0A28)) // Build number
488
_, _ = buf.Write(make([]byte, 3)) // Reserved
489
_ = buf.WriteByte(0x0F) // NTLM revision
490
491
return buf.Bytes()
492
}
493
494
// CreateNTLMChallengePacket creates an NTLM challenge packet (for testing)
495
func CreateNTLMChallengePacket(challenge []byte, targetInfo []byte) []byte {
496
var buf bytes.Buffer
497
498
// NTLMSSP signature
499
_, _ = buf.WriteString("NTLMSSP")
500
_ = buf.WriteByte(0x00)
501
502
// Message type (2 = Challenge)
503
_ = binary.Write(&buf, binary.LittleEndian, uint32(2))
504
505
// Target name fields
506
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
507
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
508
_ = binary.Write(&buf, binary.LittleEndian, uint32(56)) // TargetNameBufferOffset
509
510
// Negotiate flags
511
flags := uint32(NTLMSSP_NEGOTIATE_56 |
512
NTLMSSP_NEGOTIATE_128 |
513
NTLMSSP_NEGOTIATE_VERSION |
514
NTLMSSP_NEGOTIATE_TARGET_INFO |
515
NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY |
516
NTLMSSP_TARGET_TYPE_SERVER |
517
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
518
NTLMSSP_NEGOTIATE_NTLM |
519
NTLMSSP_NEGOTIATE_UNICODE)
520
_ = binary.Write(&buf, binary.LittleEndian, flags)
521
522
// Challenge
523
_, _ = buf.Write(challenge)
524
525
// Reserved
526
_, _ = buf.Write(make([]byte, 8))
527
528
// Target info fields
529
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(targetInfo)))
530
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(targetInfo)))
531
_ = binary.Write(&buf, binary.LittleEndian, uint32(56)) // TargetInfoBufferOffset
532
533
// Version
534
_ = buf.WriteByte(0x05) // Major version
535
_ = buf.WriteByte(0x02) // Minor version
536
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0A28)) // Build number
537
_, _ = buf.Write(make([]byte, 3)) // Reserved
538
_ = buf.WriteByte(0x0F) // NTLM revision
539
540
// Target info
541
_, _ = buf.Write(targetInfo)
542
543
return buf.Bytes()
544
}
545
546
// CreateNTLMAuthPacket creates an NTLM authenticate packet
547
func CreateNTLMAuthPacket(username, password, domain, workstation string, challenge []byte, lmResponse, ntResponse []byte) []byte {
548
var buf bytes.Buffer
549
550
// NTLMSSP signature
551
_, _ = buf.WriteString("NTLMSSP")
552
_ = buf.WriteByte(0x00)
553
554
// Message type (3 = Authenticate)
555
_ = binary.Write(&buf, binary.LittleEndian, uint32(3))
556
557
// Calculate offsets
558
baseOffset := uint32(72) // Header size (assuming Version is present)
559
560
lmOffset := baseOffset
561
ntOffset := lmOffset + uint32(len(lmResponse))
562
domainOffset := ntOffset + uint32(len(ntResponse))
563
userOffset := domainOffset + uint32(len(domain))
564
workOffset := userOffset + uint32(len(username))
565
sessionKeyOffset := workOffset + uint32(len(workstation))
566
567
// LM response fields
568
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(lmResponse)))
569
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(lmResponse)))
570
_ = binary.Write(&buf, binary.LittleEndian, uint32(lmOffset))
571
572
// NT response fields
573
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(ntResponse)))
574
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(ntResponse)))
575
_ = binary.Write(&buf, binary.LittleEndian, uint32(ntOffset))
576
577
// Domain name fields
578
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(domain)))
579
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(domain)))
580
_ = binary.Write(&buf, binary.LittleEndian, uint32(domainOffset))
581
582
// Username fields
583
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(username)))
584
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(username)))
585
_ = binary.Write(&buf, binary.LittleEndian, uint32(userOffset))
586
587
// Workstation name fields
588
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(workstation)))
589
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(workstation)))
590
_ = binary.Write(&buf, binary.LittleEndian, uint32(workOffset))
591
592
// Encrypted random session key fields
593
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
594
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
595
_ = binary.Write(&buf, binary.LittleEndian, uint32(sessionKeyOffset))
596
597
// Negotiate flags
598
flags := uint32(NTLMSSP_NEGOTIATE_56 |
599
NTLMSSP_NEGOTIATE_128 |
600
NTLMSSP_NEGOTIATE_VERSION |
601
NTLMSSP_NEGOTIATE_TARGET_INFO |
602
NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY |
603
NTLMSSP_TARGET_TYPE_SERVER |
604
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
605
NTLMSSP_NEGOTIATE_NTLM |
606
NTLMSSP_NEGOTIATE_UNICODE)
607
_ = binary.Write(&buf, binary.LittleEndian, flags)
608
609
// Version
610
_ = buf.WriteByte(0x05) // Major version
611
_ = buf.WriteByte(0x02) // Minor version
612
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0A28)) // Build number
613
_, _ = buf.Write(make([]byte, 3)) // Reserved
614
_ = buf.WriteByte(0x0F) // NTLM revision
615
616
// LM response
617
_, _ = buf.Write(lmResponse)
618
619
// NT response
620
_, _ = buf.Write(ntResponse)
621
622
// Domain name
623
_, _ = buf.WriteString(domain)
624
625
// Username
626
_, _ = buf.WriteString(username)
627
628
// Workstation name
629
_, _ = buf.WriteString(workstation)
630
631
return buf.Bytes()
632
}
633
634
// Helper function to create LM hash response
635
func CreateLMResponse(challenge []byte, password string) []byte {
636
// Create a minimal Type 2 challenge packet to satisfy ntlmssp
637
type2 := CreateNTLMChallengePacket(challenge, []byte{})
638
639
// Generate Type 3 authenticate packet
640
// We use empty username/domain as we only need the hash response
641
authMsg, err := ntlmssp.NewAuthenticateMessage(type2, "", password, nil)
642
if err != nil {
643
return nil
644
}
645
646
// Parse the response to extract LM response
647
// LM Response Len is at offset 12 (2 bytes)
648
// LM Response Offset is at offset 16 (4 bytes)
649
if len(authMsg) < 20 {
650
return nil
651
}
652
653
lmLen := binary.LittleEndian.Uint16(authMsg[12:14])
654
lmOffset := binary.LittleEndian.Uint32(authMsg[16:20])
655
656
if int(lmOffset)+int(lmLen) > len(authMsg) {
657
return nil
658
}
659
660
return authMsg[lmOffset : lmOffset+uint32(lmLen)]
661
}
662
663
// Helper function to create NT hash response
664
func CreateNTResponse(challenge []byte, password string) []byte {
665
// Create a minimal Type 2 challenge packet to satisfy ntlmssp
666
type2 := CreateNTLMChallengePacket(challenge, []byte{})
667
668
// Generate Type 3 authenticate packet
669
authMsg, err := ntlmssp.NewAuthenticateMessage(type2, "", password, nil)
670
if err != nil {
671
return nil
672
}
673
674
// Parse the response to extract NT response
675
// NT Response Len is at offset 20 (2 bytes)
676
// NT Response Offset is at offset 24 (4 bytes)
677
if len(authMsg) < 28 {
678
return nil
679
}
680
681
ntLen := binary.LittleEndian.Uint16(authMsg[20:22])
682
ntOffset := binary.LittleEndian.Uint32(authMsg[24:28])
683
684
if int(ntOffset)+int(ntLen) > len(authMsg) {
685
return nil
686
}
687
688
return authMsg[ntOffset : ntOffset+uint32(ntLen)]
689
}
690
691
// CreateSMBv2NegotiatePacket creates an SMBv2 negotiate protocol packet
692
func CreateSMBv2NegotiatePacket() []byte {
693
var buf bytes.Buffer
694
695
// SMB2 header
696
_ = buf.WriteByte(0xFE) // Protocol ID
697
_, _ = buf.WriteString("SMB")
698
_ = buf.WriteByte(0x00) // Protocol ID
699
700
// Command (Negotiate Protocol)
701
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0000))
702
703
// Status
704
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
705
706
// Flags
707
_ = buf.WriteByte(0x00)
708
709
// Next command
710
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0000))
711
712
// Message ID
713
_ = binary.Write(&buf, binary.LittleEndian, uint64(0x0000000000000001))
714
715
// Reserved
716
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
717
718
// Tree ID
719
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000000))
720
721
// Session ID
722
_ = binary.Write(&buf, binary.LittleEndian, uint64(0x0000000000000000))
723
724
// Signature
725
_, _ = buf.Write(make([]byte, 16))
726
727
// Structure size
728
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x24))
729
730
// Dialect count
731
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0001))
732
733
// Security mode
734
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0001))
735
736
// Reserved
737
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0000))
738
739
// Capabilities
740
_ = binary.Write(&buf, binary.LittleEndian, uint32(0x00000001))
741
742
// Client GUID
743
_, _ = buf.Write(make([]byte, 16))
744
745
// Client start time
746
_ = binary.Write(&buf, binary.LittleEndian, uint64(0x0000000000000000))
747
748
// Dialects
749
_ = binary.Write(&buf, binary.LittleEndian, uint16(0x0311)) // SMB 3.1.1
750
751
return buf.Bytes()
752
}
753
754
// ParseSMBResponse parses an SMB response packet
755
func ParseSMBResponse(data []byte) (*SMBHeader, error) {
756
if len(data) < 32 {
757
return nil, fmt.Errorf("SMB response too short: %d bytes", len(data))
758
}
759
760
header := &SMBHeader{}
761
762
// Check protocol ID
763
if data[0] != 0xFF || data[1] != 'S' || data[2] != 'M' || data[3] != 'B' {
764
return nil, fmt.Errorf("invalid SMB protocol ID")
765
}
766
767
// Parse header fields
768
header.Command = data[4]
769
header.Status = binary.LittleEndian.Uint32(data[5:9])
770
header.Flags = data[9]
771
header.Flags2 = binary.LittleEndian.Uint16(data[10:12])
772
header.PIDHigh = binary.LittleEndian.Uint16(data[12:14])
773
copy(header.Signature[:], data[14:22])
774
header.Reserved = binary.LittleEndian.Uint16(data[22:24])
775
header.TreeID = binary.LittleEndian.Uint16(data[24:26])
776
header.ProcessID = binary.LittleEndian.Uint16(data[26:28])
777
header.UserID = binary.LittleEndian.Uint16(data[28:30])
778
header.MultiplexID = binary.LittleEndian.Uint16(data[30:32])
779
780
return header, nil
781
}
782
783