1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Gabriel Potter
5
6"""
7SMB (Server Message Block), also known as CIFS - version 2
8
9.. note::
10 You will find more complete documentation for this layer over at
11 `SMB <https://scapy.readthedocs.io/en/latest/layers/smb.html>`_
12"""
13
14import os
15import collections
16import functools
17import hashlib
18import struct
19
20from scapy.config import conf, crypto_validator
21from scapy.error import log_runtime
22from scapy.packet import Packet, bind_layers, bind_top_down
23from scapy.fields import (
24 ByteEnumField,
25 ByteField,
26 ConditionalField,
27 FieldLenField,
28 FieldListField,
29 FlagValue,
30 FlagsField,
31 IP6Field,
32 IPField,
33 IntEnumField,
34 IntField,
35 LEIntField,
36 LEIntEnumField,
37 LELongField,
38 LenField,
39 LEShortEnumField,
40 LEShortField,
41 MultipleTypeField,
42 PadField,
43 PacketField,
44 PacketLenField,
45 PacketListField,
46 ReversePadField,
47 ScalingField,
48 ShortEnumField,
49 ShortField,
50 StrFieldUtf16,
51 StrFixedLenField,
52 StrLenField,
53 StrLenFieldUtf16,
54 StrNullFieldUtf16,
55 ThreeBytesField,
56 UTCTimeField,
57 UUIDField,
58 XLEIntField,
59 XLELongField,
60 XLEShortField,
61 XStrLenField,
62 XStrFixedLenField,
63 YesNoByteField,
64)
65from scapy.sessions import DefaultSession
66from scapy.supersocket import StreamSocket
67
68if conf.crypto_valid:
69 from scapy.libs.rfc3961 import SP800108_KDFCTR
70
71from scapy.layers.gssapi import GSSAPI_BLOB
72from scapy.layers.netbios import NBTSession
73from scapy.layers.ntlm import (
74 _NTLMPayloadField,
75 _NTLMPayloadPacket,
76 _NTLM_ENUM,
77 _NTLM_post_build,
78)
79
80
81# EnumField
82SMB_DIALECTS = {
83 0x0202: "SMB 2.002",
84 0x0210: "SMB 2.1",
85 0x02FF: "SMB 2.???",
86 0x0300: "SMB 3.0",
87 0x0302: "SMB 3.0.2",
88 0x0311: "SMB 3.1.1",
89}
90
91# SMB2 sect 3.3.5.15 + [MS-ERREF]
92STATUS_ERREF = {
93 0x00000000: "STATUS_SUCCESS",
94 0x00000103: "STATUS_PENDING",
95 0x0000010B: "STATUS_NOTIFY_CLEANUP",
96 0x0000010C: "STATUS_NOTIFY_ENUM_DIR",
97 0x00000532: "ERROR_PASSWORD_EXPIRED",
98 0x00000533: "ERROR_ACCOUNT_DISABLED",
99 0x80000005: "STATUS_BUFFER_OVERFLOW",
100 0x80000006: "STATUS_NO_MORE_FILES",
101 0x8000002D: "STATUS_STOPPED_ON_SYMLINK",
102 0xC0000003: "STATUS_INVALID_INFO_CLASS",
103 0xC0000004: "STATUS_INFO_LENGTH_MISMATCH",
104 0xC000000D: "STATUS_INVALID_PARAMETER",
105 0xC000000F: "STATUS_NO_SUCH_FILE",
106 0xC0000016: "STATUS_MORE_PROCESSING_REQUIRED",
107 0xC0000022: "STATUS_ACCESS_DENIED",
108 0xC0000033: "STATUS_OBJECT_NAME_INVALID",
109 0xC0000034: "STATUS_OBJECT_NAME_NOT_FOUND",
110 0xC0000043: "STATUS_SHARING_VIOLATION",
111 0xC000006D: "STATUS_LOGON_FAILURE",
112 0xC000006E: "STATUS_ACCOUNT_RESTRICTION",
113 0xC0000071: "STATUS_PASSWORD_EXPIRED",
114 0xC0000072: "STATUS_ACCOUNT_DISABLED",
115 0xC000009A: "STATUS_INSUFFICIENT_RESOURCES",
116 0xC00000BA: "STATUS_FILE_IS_A_DIRECTORY",
117 0xC00000BB: "STATUS_NOT_SUPPORTED",
118 0xC00000C9: "STATUS_NETWORK_NAME_DELETED",
119 0xC00000CC: "STATUS_BAD_NETWORK_NAME",
120 0xC0000120: "STATUS_CANCELLED",
121 0xC0000128: "STATUS_FILE_CLOSED", # backup error for older Win versions
122 0xC000015B: "STATUS_LOGON_TYPE_NOT_GRANTED",
123 0xC000019C: "STATUS_FS_DRIVER_REQUIRED",
124 0xC0000203: "STATUS_USER_SESSION_DELETED",
125 0xC000020C: "STATUS_CONNECTION_DISCONNECTED",
126 0xC0000225: "STATUS_NOT_FOUND",
127 0xC0000257: "STATUS_PATH_NOT_COVERED",
128 0xC000035C: "STATUS_NETWORK_SESSION_EXPIRED",
129}
130
131# SMB2 sect 2.1.2.1
132REPARSE_TAGS = {
133 0x00000000: "IO_REPARSE_TAG_RESERVED_ZERO",
134 0x00000001: "IO_REPARSE_TAG_RESERVED_ONE",
135 0x00000002: "IO_REPARSE_TAG_RESERVED_TWO",
136 0xA0000003: "IO_REPARSE_TAG_MOUNT_POINT",
137 0xC0000004: "IO_REPARSE_TAG_HSM",
138 0x80000005: "IO_REPARSE_TAG_DRIVE_EXTENDER",
139 0x80000006: "IO_REPARSE_TAG_HSM2",
140 0x80000007: "IO_REPARSE_TAG_SIS",
141 0x80000008: "IO_REPARSE_TAG_WIM",
142 0x80000009: "IO_REPARSE_TAG_CSV",
143 0x8000000A: "IO_REPARSE_TAG_DFS",
144 0x8000000B: "IO_REPARSE_TAG_FILTER_MANAGER",
145 0xA000000C: "IO_REPARSE_TAG_SYMLINK",
146 0xA0000010: "IO_REPARSE_TAG_IIS_CACHE",
147 0x80000012: "IO_REPARSE_TAG_DFSR",
148 0x80000013: "IO_REPARSE_TAG_DEDUP",
149 0xC0000014: "IO_REPARSE_TAG_APPXSTRM",
150 0x80000014: "IO_REPARSE_TAG_NFS",
151 0x80000015: "IO_REPARSE_TAG_FILE_PLACEHOLDER",
152 0x80000016: "IO_REPARSE_TAG_DFM",
153 0x80000017: "IO_REPARSE_TAG_WOF",
154 0x80000018: "IO_REPARSE_TAG_WCI",
155 0x90001018: "IO_REPARSE_TAG_WCI_1",
156 0xA0000019: "IO_REPARSE_TAG_GLOBAL_REPARSE",
157 0x9000001A: "IO_REPARSE_TAG_CLOUD",
158 0x9000101A: "IO_REPARSE_TAG_CLOUD_1",
159 0x9000201A: "IO_REPARSE_TAG_CLOUD_2",
160 0x9000301A: "IO_REPARSE_TAG_CLOUD_3",
161 0x9000401A: "IO_REPARSE_TAG_CLOUD_4",
162 0x9000501A: "IO_REPARSE_TAG_CLOUD_5",
163 0x9000601A: "IO_REPARSE_TAG_CLOUD_6",
164 0x9000701A: "IO_REPARSE_TAG_CLOUD_7",
165 0x9000801A: "IO_REPARSE_TAG_CLOUD_8",
166 0x9000901A: "IO_REPARSE_TAG_CLOUD_9",
167 0x9000A01A: "IO_REPARSE_TAG_CLOUD_A",
168 0x9000B01A: "IO_REPARSE_TAG_CLOUD_B",
169 0x9000C01A: "IO_REPARSE_TAG_CLOUD_C",
170 0x9000D01A: "IO_REPARSE_TAG_CLOUD_D",
171 0x9000E01A: "IO_REPARSE_TAG_CLOUD_E",
172 0x9000F01A: "IO_REPARSE_TAG_CLOUD_F",
173 0x8000001B: "IO_REPARSE_TAG_APPEXECLINK",
174 0x9000001C: "IO_REPARSE_TAG_PROJFS",
175 0xA000001D: "IO_REPARSE_TAG_LX_SYMLINK",
176 0x8000001E: "IO_REPARSE_TAG_STORAGE_SYNC",
177 0xA000001F: "IO_REPARSE_TAG_WCI_TOMBSTONE",
178 0x80000020: "IO_REPARSE_TAG_UNHANDLED",
179 0x80000021: "IO_REPARSE_TAG_ONEDRIVE",
180 0xA0000022: "IO_REPARSE_TAG_PROJFS_TOMBSTONE",
181 0x80000023: "IO_REPARSE_TAG_AF_UNIX",
182 0x80000024: "IO_REPARSE_TAG_LX_FIFO",
183 0x80000025: "IO_REPARSE_TAG_LX_CHR",
184 0x80000026: "IO_REPARSE_TAG_LX_BLK",
185 0xA0000027: "IO_REPARSE_TAG_WCI_LINK",
186 0xA0001027: "IO_REPARSE_TAG_WCI_LINK_1",
187}
188
189# SMB2 sect 2.2.1.1
190SMB2_COM = {
191 0x0000: "SMB2_NEGOTIATE",
192 0x0001: "SMB2_SESSION_SETUP",
193 0x0002: "SMB2_LOGOFF",
194 0x0003: "SMB2_TREE_CONNECT",
195 0x0004: "SMB2_TREE_DISCONNECT",
196 0x0005: "SMB2_CREATE",
197 0x0006: "SMB2_CLOSE",
198 0x0007: "SMB2_FLUSH",
199 0x0008: "SMB2_READ",
200 0x0009: "SMB2_WRITE",
201 0x000A: "SMB2_LOCK",
202 0x000B: "SMB2_IOCTL",
203 0x000C: "SMB2_CANCEL",
204 0x000D: "SMB2_ECHO",
205 0x000E: "SMB2_QUERY_DIRECTORY",
206 0x000F: "SMB2_CHANGE_NOTIFY",
207 0x0010: "SMB2_QUERY_INFO",
208 0x0011: "SMB2_SET_INFO",
209 0x0012: "SMB2_OPLOCK_BREAK",
210}
211
212# EnumField
213SMB2_NEGOTIATE_CONTEXT_TYPES = {
214 0x0001: "SMB2_PREAUTH_INTEGRITY_CAPABILITIES",
215 0x0002: "SMB2_ENCRYPTION_CAPABILITIES",
216 0x0003: "SMB2_COMPRESSION_CAPABILITIES",
217 0x0005: "SMB2_NETNAME_NEGOTIATE_CONTEXT_ID",
218 0x0006: "SMB2_TRANSPORT_CAPABILITIES",
219 0x0007: "SMB2_RDMA_TRANSFORM_CAPABILITIES",
220 0x0008: "SMB2_SIGNING_CAPABILITIES",
221}
222
223# FlagField
224SMB2_CAPABILITIES = {
225 0x00000001: "DFS",
226 0x00000002: "LEASING",
227 0x00000004: "LARGE_MTU",
228 0x00000008: "MULTI_CHANNEL",
229 0x00000010: "PERSISTENT_HANDLES",
230 0x00000020: "DIRECTORY_LEASING",
231 0x00000040: "ENCRYPTION",
232}
233SMB2_SECURITY_MODE = {
234 0x01: "SIGNING_ENABLED",
235 0x02: "SIGNING_REQUIRED",
236}
237
238# [MS-SMB2] 2.2.3.1.3
239SMB2_COMPRESSION_ALGORITHMS = {
240 0x0000: "None",
241 0x0001: "LZNT1",
242 0x0002: "LZ77",
243 0x0003: "LZ77 + Huffman",
244 0x0004: "Pattern_V1",
245}
246
247# [MS-SMB2] sect 2.2.3.1.2
248SMB2_ENCRYPTION_CIPHERS = {
249 0x0001: "AES-128-CCM",
250 0x0002: "AES-128-GCM",
251 0x0003: "AES-256-CCM",
252 0x0004: "AES-256-GCM",
253}
254
255# [MS-SMB2] sect 2.2.3.1.7
256SMB2_SIGNING_ALGORITHMS = {
257 0x0000: "HMAC-SHA256",
258 0x0001: "AES-CMAC",
259 0x0002: "AES-GMAC",
260}
261
262# sect [MS-SMB2] 2.2.13.1.1
263SMB2_ACCESS_FLAGS_FILE = {
264 0x00000001: "FILE_READ_DATA",
265 0x00000002: "FILE_WRITE_DATA",
266 0x00000004: "FILE_APPEND_DATA",
267 0x00000008: "FILE_READ_EA",
268 0x00000010: "FILE_WRITE_EA",
269 0x00000040: "FILE_DELETE_CHILD",
270 0x00000020: "FILE_EXECUTE",
271 0x00000080: "FILE_READ_ATTRIBUTES",
272 0x00000100: "FILE_WRITE_ATTRIBUTES",
273 0x00010000: "DELETE",
274 0x00020000: "READ_CONTROL",
275 0x00040000: "WRITE_DAC",
276 0x00080000: "WRITE_OWNER",
277 0x00100000: "SYNCHRONIZE",
278 0x01000000: "ACCESS_SYSTEM_SECURITY",
279 0x02000000: "MAXIMUM_ALLOWED",
280 0x10000000: "GENERIC_ALL",
281 0x20000000: "GENERIC_EXECUTE",
282 0x40000000: "GENERIC_WRITE",
283 0x80000000: "GENERIC_READ",
284}
285
286# sect [MS-SMB2] 2.2.13.1.2
287SMB2_ACCESS_FLAGS_DIRECTORY = {
288 0x00000001: "FILE_LIST_DIRECTORY",
289 0x00000002: "FILE_ADD_FILE",
290 0x00000004: "FILE_ADD_SUBDIRECTORY",
291 0x00000008: "FILE_READ_EA",
292 0x00000010: "FILE_WRITE_EA",
293 0x00000020: "FILE_TRAVERSE",
294 0x00000040: "FILE_DELETE_CHILD",
295 0x00000080: "FILE_READ_ATTRIBUTES",
296 0x00000100: "FILE_WRITE_ATTRIBUTES",
297 0x00010000: "DELETE",
298 0x00020000: "READ_CONTROL",
299 0x00040000: "WRITE_DAC",
300 0x00080000: "WRITE_OWNER",
301 0x00100000: "SYNCHRONIZE",
302 0x01000000: "ACCESS_SYSTEM_SECURITY",
303 0x02000000: "MAXIMUM_ALLOWED",
304 0x10000000: "GENERIC_ALL",
305 0x20000000: "GENERIC_EXECUTE",
306 0x40000000: "GENERIC_WRITE",
307 0x80000000: "GENERIC_READ",
308}
309
310# [MS-SRVS] sec 2.2.2.4
311SRVSVC_SHARE_TYPES = {
312 0x00000000: "DISKTREE",
313 0x00000001: "PRINTQ",
314 0x00000002: "DEVICE",
315 0x00000003: "IPC",
316 0x02000000: "CLUSTER_FS",
317 0x04000000: "CLUSTER_SOFS",
318 0x08000000: "CLUSTER_DFS",
319}
320
321
322# [MS-FSCC] sec 2.6
323FileAttributes = {
324 0x00000001: "FILE_ATTRIBUTE_READONLY",
325 0x00000002: "FILE_ATTRIBUTE_HIDDEN",
326 0x00000004: "FILE_ATTRIBUTE_SYSTEM",
327 0x00000010: "FILE_ATTRIBUTE_DIRECTORY",
328 0x00000020: "FILE_ATTRIBUTE_ARCHIVE",
329 0x00000080: "FILE_ATTRIBUTE_NORMAL",
330 0x00000100: "FILE_ATTRIBUTE_TEMPORARY",
331 0x00000200: "FILE_ATTRIBUTE_SPARSE_FILE",
332 0x00000400: "FILE_ATTRIBUTE_REPARSE_POINT",
333 0x00000800: "FILE_ATTRIBUTE_COMPRESSED",
334 0x00001000: "FILE_ATTRIBUTE_OFFLINE",
335 0x00002000: "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED",
336 0x00004000: "FILE_ATTRIBUTE_ENCRYPTED",
337 0x00008000: "FILE_ATTRIBUTE_INTEGRITY_STREAM",
338 0x00020000: "FILE_ATTRIBUTE_NO_SCRUB_DATA",
339 0x00040000: "FILE_ATTRIBUTE_RECALL_ON_OPEN",
340 0x00080000: "FILE_ATTRIBUTE_PINNED",
341 0x00100000: "FILE_ATTRIBUTE_UNPINNED",
342 0x00400000: "FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS",
343}
344
345
346# [MS-FSCC] sect 2.4
347FileInformationClasses = {
348 0x01: "FileDirectoryInformation",
349 0x02: "FileFullDirectoryInformation",
350 0x03: "FileBothDirectoryInformation",
351 0x04: "FileBasicInformation",
352 0x05: "FileStandardInformation",
353 0x06: "FileInternalInformation",
354 0x07: "FileEaInformation",
355 0x08: "FileAccessInformation",
356 0x0A: "FileRenameInformation",
357 0x0E: "FilePositionInformation",
358 0x10: "FileModeInformation",
359 0x11: "FileAlignmentInformation",
360 0x12: "FileAllInformation",
361 0x22: "FileNetworkOpenInformation",
362 0x25: "FileIdBothDirectoryInformation",
363 0x26: "FileIdFullDirectoryInformation",
364 0x0C: "FileNamesInformation",
365 0x30: "FileNormalizedNameInformation",
366 0x3C: "FileIdExtdDirectoryInformation",
367}
368_FileInformationClasses = {}
369
370
371# [MS-FSCC] 2.1.7 FILE_NAME_INFORMATION
372
373
374class FILE_NAME_INFORMATION(Packet):
375 fields_desc = [
376 FieldLenField("FileNameLength", None, length_of="FileName", fmt="<I"),
377 StrLenFieldUtf16("FileName", "", length_from=lambda pkt: pkt.FileNameLength),
378 ]
379
380 def default_payload_class(self, s):
381 return conf.padding_layer
382
383
384# [MS-FSCC] 2.4.1 FileAccessInformation
385
386
387class FileAccessInformation(Packet):
388 fields_desc = [
389 FlagsField("AccessFlags", 0, -32, SMB2_ACCESS_FLAGS_FILE),
390 ]
391
392 def default_payload_class(self, s):
393 return conf.padding_layer
394
395
396# [MS-FSCC] 2.4.3 FileAlignmentInformation
397
398
399class FileAlignmentInformation(Packet):
400 fields_desc = [
401 LEIntEnumField(
402 "AccessFlags",
403 0,
404 {
405 0x00000000: "FILE_BYTE_ALIGNMENT",
406 0x00000001: "FILE_WORD_ALIGNMENT",
407 0x00000003: "FILE_LONG_ALIGNMENT",
408 0x00000007: "FILE_QUAD_ALIGNMENT",
409 0x0000000F: "FILE_OCTA_ALIGNMENT",
410 0x0000001F: "FILE_32_BYTE_ALIGNMENT",
411 0x0000003F: "FILE_64_BYTE_ALIGNMENT",
412 0x0000007F: "FILE_128_BYTE_ALIGNMENT",
413 0x000000FF: "FILE_256_BYTE_ALIGNMENT",
414 0x000001FF: "FILE_512_BYTE_ALIGNMENT",
415 },
416 ),
417 ]
418
419 def default_payload_class(self, s):
420 return conf.padding_layer
421
422
423# [MS-FSCC] 2.4.5 FileAlternateNameInformation
424
425
426class FileAlternateNameInformation(Packet):
427 fields_desc = [
428 FieldLenField("FileNameLength", None, length_of="FileName", fmt="<I"),
429 StrLenFieldUtf16("FileName", b"", length_from=lambda pkt: pkt.FileNameLength),
430 ]
431
432
433# [MS-FSCC] 2.4.7 FileBasicInformation
434
435
436class FileBasicInformation(Packet):
437 fields_desc = [
438 UTCTimeField(
439 "CreationTime",
440 None,
441 fmt="<Q",
442 epoch=[1601, 1, 1, 0, 0, 0],
443 custom_scaling=1e7,
444 ),
445 UTCTimeField(
446 "LastAccessTime",
447 None,
448 fmt="<Q",
449 epoch=[1601, 1, 1, 0, 0, 0],
450 custom_scaling=1e7,
451 ),
452 UTCTimeField(
453 "LastWriteTime",
454 None,
455 fmt="<Q",
456 epoch=[1601, 1, 1, 0, 0, 0],
457 custom_scaling=1e7,
458 ),
459 UTCTimeField(
460 "ChangeTime",
461 None,
462 fmt="<Q",
463 epoch=[1601, 1, 1, 0, 0, 0],
464 custom_scaling=1e7,
465 ),
466 FlagsField("FileAttributes", 0x00000080, -32, FileAttributes),
467 IntField("Reserved", 0),
468 ]
469
470 def default_payload_class(self, s):
471 return conf.padding_layer
472
473
474# [MS-FSCC] 2.4.12 FileEaInformation
475
476
477class FileEaInformation(Packet):
478 fields_desc = [
479 LEIntField("EaSize", 0),
480 ]
481
482 def default_payload_class(self, s):
483 return conf.padding_layer
484
485
486# [MS-FSCC] 2.4.29 FileNetworkOpenInformation
487
488
489class FileNetworkOpenInformation(Packet):
490 fields_desc = [
491 UTCTimeField(
492 "CreationTime",
493 None,
494 fmt="<Q",
495 epoch=[1601, 1, 1, 0, 0, 0],
496 custom_scaling=1e7,
497 ),
498 UTCTimeField(
499 "LastAccessTime",
500 None,
501 fmt="<Q",
502 epoch=[1601, 1, 1, 0, 0, 0],
503 custom_scaling=1e7,
504 ),
505 UTCTimeField(
506 "LastWriteTime",
507 None,
508 fmt="<Q",
509 epoch=[1601, 1, 1, 0, 0, 0],
510 custom_scaling=1e7,
511 ),
512 UTCTimeField(
513 "ChangeTime",
514 None,
515 fmt="<Q",
516 epoch=[1601, 1, 1, 0, 0, 0],
517 custom_scaling=1e7,
518 ),
519 LELongField("AllocationSize", 4096),
520 LELongField("EndOfFile", 0),
521 FlagsField("FileAttributes", 0x00000080, -32, FileAttributes),
522 IntField("Reserved2", 0),
523 ]
524
525 def default_payload_class(self, s):
526 return conf.padding_layer
527
528
529# [MS-FSCC] 2.4.8 FileBothDirectoryInformation
530
531
532class FILE_BOTH_DIR_INFORMATION(Packet):
533 fields_desc = (
534 [
535 LEIntField("Next", None), # 0 = no next entry
536 LEIntField("FileIndex", 0),
537 ]
538 + (
539 FileNetworkOpenInformation.fields_desc[:4]
540 + FileNetworkOpenInformation.fields_desc[4:6][::-1]
541 + [FileNetworkOpenInformation.fields_desc[6]]
542 )
543 + [
544 FieldLenField("FileNameLength", None, fmt="<I", length_of="FileName"),
545 MultipleTypeField(
546 # "If FILE_ATTRIBUTE_REPARSE_POINT is set in the FileAttributes field,
547 # this field MUST contain a reparse tag as specified in section
548 # 2.1.2.1."
549 [
550 (
551 LEIntEnumField("EaSize", 0, REPARSE_TAGS),
552 lambda pkt: pkt.FileAttributes.FILE_ATTRIBUTE_REPARSE_POINT,
553 )
554 ],
555 LEIntField("EaSize", 0),
556 ),
557 ByteField("ShortNameLength", 0),
558 ByteField("Reserved1", 0),
559 StrFixedLenField("ShortName", b"", length=24),
560 PadField(
561 StrLenFieldUtf16(
562 "FileName", b".", length_from=lambda pkt: pkt.FileNameLength
563 ),
564 align=8,
565 ),
566 ]
567 )
568
569 def default_payload_class(self, s):
570 return conf.padding_layer
571
572
573class _NextPacketListField(PacketListField):
574 def addfield(self, pkt, s, val):
575 # we use this field to set NextEntryOffset
576 res = b""
577 for i, v in enumerate(val):
578 x = self.i2m(pkt, v)
579 if v.Next is None and i != len(val) - 1:
580 x = struct.pack("<I", len(x)) + x[4:]
581 res += x
582 return s + res
583
584
585class FileBothDirectoryInformation(Packet):
586 fields_desc = [
587 _NextPacketListField(
588 "files",
589 [],
590 FILE_BOTH_DIR_INFORMATION,
591 max_count=1000,
592 ),
593 ]
594
595
596# [MS-FSCC] 2.4.14 FileFullDirectoryInformation
597
598
599class FILE_FULL_DIR_INFORMATION(Packet):
600 fields_desc = FILE_BOTH_DIR_INFORMATION.fields_desc[:11] + [
601 FILE_BOTH_DIR_INFORMATION.fields_desc[-1]
602 ]
603
604
605class FileFullDirectoryInformation(Packet):
606 fields_desc = [
607 _NextPacketListField(
608 "files",
609 [],
610 FILE_FULL_DIR_INFORMATION,
611 max_count=1000,
612 ),
613 ]
614
615
616# [MS-FSCC] 2.4.17 FileIdBothDirectoryInformation
617
618
619class FILE_ID_BOTH_DIR_INFORMATION(Packet):
620 fields_desc = FILE_BOTH_DIR_INFORMATION.fields_desc[:14] + [
621 LEShortField("Reserved2", 0),
622 LELongField("FileId", 0),
623 FILE_BOTH_DIR_INFORMATION.fields_desc[-1],
624 ]
625
626 def default_payload_class(self, s):
627 return conf.padding_layer
628
629
630class FileIdBothDirectoryInformation(Packet):
631 fields_desc = [
632 _NextPacketListField(
633 "files",
634 [],
635 FILE_ID_BOTH_DIR_INFORMATION,
636 max_count=1000, # > 65535 / len(FILE_ID_BOTH_DIR_INFORMATION())
637 ),
638 ]
639
640
641# [MS-FSCC] 2.4.22 FileInternalInformation
642
643
644class FileInternalInformation(Packet):
645 fields_desc = [
646 LELongField("IndexNumber", 0),
647 ]
648
649 def default_payload_class(self, s):
650 return conf.padding_layer
651
652
653# [MS-FSCC] 2.4.26 FileModeInformation
654
655
656class FileModeInformation(Packet):
657 fields_desc = [
658 FlagsField(
659 "Mode",
660 0,
661 -32,
662 {
663 0x00000002: "FILE_WRITE_TROUGH",
664 0x00000004: "FILE_SEQUENTIAL_ONLY",
665 0x00000008: "FILE_NO_INTERMEDIATE_BUFFERING",
666 0x00000010: "FILE_SYNCHRONOUS_IO_ALERT",
667 0x00000020: "FILE_SYNCHRONOUS_IO_NONALERT",
668 0x00001000: "FILE_DELETE_ON_CLOSE",
669 },
670 )
671 ]
672
673 def default_payload_class(self, s):
674 return conf.padding_layer
675
676
677# [MS-FSCC] 2.4.35 FilePositionInformation
678
679
680class FilePositionInformation(Packet):
681 fields_desc = [
682 LELongField("CurrentByteOffset", 0),
683 ]
684
685 def default_payload_class(self, s):
686 return conf.padding_layer
687
688
689# [MS-FSCC] 2.4.37 FileRenameInformation
690
691
692class FileRenameInformation(Packet):
693 fields_desc = [
694 YesNoByteField("ReplaceIfExists", False),
695 XStrFixedLenField("Reserved", b"", length=7),
696 LELongField("RootDirectory", 0),
697 FieldLenField("FileNameLength", 0, length_of="FileName", fmt="<I"),
698 StrLenFieldUtf16("FileName", b"", length_from=lambda pkt: pkt.FileNameLength),
699 ]
700
701 def post_build(self, pkt, pay):
702 # type: (bytes, bytes) -> bytes
703 if len(pkt) < 24:
704 # 'Length of this field MUST be the number of bytes required to make the
705 # size of this structure at least 24.'
706 pkt += (24 - len(pkt)) * b"\x00"
707 return pkt + pay
708
709 def default_payload_class(self, s):
710 return conf.padding_layer
711
712
713_FileInformationClasses[0x0A] = FileRenameInformation
714
715
716# [MS-FSCC] 2.4.41 FileStandardInformation
717
718
719class FileStandardInformation(Packet):
720 fields_desc = [
721 LELongField("AllocationSize", 4096),
722 LELongField("EndOfFile", 0),
723 LEIntField("NumberOfLinks", 1),
724 ByteField("DeletePending", 0),
725 ByteField("Directory", 0),
726 ShortField("Reserved", 0),
727 ]
728
729 def default_payload_class(self, s):
730 return conf.padding_layer
731
732
733# [MS-FSCC] 2.4.43 FileStreamInformation
734
735
736class FileStreamInformation(Packet):
737 fields_desc = [
738 LEIntField("Next", 0),
739 FieldLenField("StreamNameLength", None, length_of="StreamName", fmt="<I"),
740 LELongField("StreamSize", 0),
741 LELongField("StreamAllocationSize", 4096),
742 StrLenFieldUtf16(
743 "StreamName", b"::$DATA", length_from=lambda pkt: pkt.StreamNameLength
744 ),
745 ]
746
747
748# [MS-DTYP] sect 2.4.1
749
750
751class WINNT_SID_IDENTIFIER_AUTHORITY(Packet):
752 fields_desc = [
753 StrFixedLenField("Value", b"", length=6),
754 ]
755
756 def default_payload_class(self, payload):
757 return conf.padding_layer
758
759
760# [MS-DTYP] sect 2.4.2
761
762
763class WINNT_SID(Packet):
764 fields_desc = [
765 ByteField("Revision", 1),
766 FieldLenField("SubAuthorityCount", None, count_of="SubAuthority", fmt="B"),
767 PacketField(
768 "IdentifierAuthority",
769 WINNT_SID_IDENTIFIER_AUTHORITY(),
770 WINNT_SID_IDENTIFIER_AUTHORITY,
771 ),
772 FieldListField(
773 "SubAuthority",
774 [],
775 LEIntField("", 0),
776 count_from=lambda pkt: pkt.SubAuthorityCount,
777 ),
778 ]
779
780 def default_payload_class(self, payload):
781 return conf.padding_layer
782
783 def summary(self):
784 return "S-%s-%s%s" % (
785 self.Revision,
786 struct.unpack(">Q", b"\x00\x00" + self.IdentifierAuthority.Value)[0],
787 ("-%s" % "-".join(str(x) for x in self.SubAuthority))
788 if self.SubAuthority
789 else "",
790 )
791
792
793# [MS-DTYP] sect 2.4.3
794
795_WINNT_ACCESS_MASK = {
796 0x80000000: "GENERIC_READ",
797 0x40000000: "GENERIC_WRITE",
798 0x20000000: "GENERIC_EXECUTE",
799 0x10000000: "GENERIC_ALL",
800 0x02000000: "MAXIMUM_ALLOWED",
801 0x01000000: "ACCESS_SYSTEM_SECURITY",
802 0x00100000: "SYNCHRONIZE",
803 0x00080000: "WRITE_OWNER",
804 0x00040000: "WRITE_DACL",
805 0x00020000: "READ_CONTROL",
806 0x00010000: "DELETE",
807}
808
809
810# [MS-DTYP] sect 2.4.4.1
811
812
813class WINNT_ACE_HEADER(Packet):
814 fields_desc = [
815 ByteEnumField(
816 "AceType",
817 0,
818 {
819 0x00: "ACCESS_ALLOWED",
820 0x01: "ACCESS_DENIED",
821 0x02: "SYSTEM_AUDIT",
822 0x03: "SYSTEM_ALARM",
823 0x04: "ACCESS_ALLOWED_COMPOUND",
824 0x05: "ACCESS_ALLOWED_OBJECT",
825 0x06: "ACCESS_DENIED_OBJECT",
826 0x07: "SYSTEM_AUDIT_OBJECT",
827 0x08: "SYSTEM_ALARM_OBJECT",
828 0x09: "ACCESS_ALLOWED_CALLBACK",
829 0x0A: "ACCESS_DENIED_CALLBACK",
830 0x0B: "ACCESS_ALLOWED_CALLBACK_OBJECT",
831 0x0C: "ACCESS_DENIED_CALLBACK_OBJECT",
832 0x0D: "SYSTEM_AUDIT_CALLBACK",
833 0x0E: "SYSTEM_ALARM_CALLBACK",
834 0x0F: "SYSTEM_AUDIT_CALLBACK_OBJECT",
835 0x10: "SYSTEM_ALARM_CALLBACK_OBJECT",
836 0x11: "SYSTEM_MANDATORY_LABEL",
837 0x12: "SYSTEM_RESOURCE_ATTRIBUTE",
838 0x13: "SYSTEM_SCOPED_POLICY_ID",
839 },
840 ),
841 FlagsField(
842 "AceFlags",
843 0,
844 8,
845 {
846 0x01: "OBJECT_INHERIT",
847 0x02: "CONTAINER_INHERIT",
848 0x04: "NO_PROPAGATE_INHERIT",
849 0x08: "INHERIT_ONLY",
850 0x10: "INHERITED_ACE",
851 0x40: "SUCCESSFUL_ACCESS",
852 0x80: "FAILED_ACCESS",
853 },
854 ),
855 LenField("AceSize", None, fmt="<H", adjust=lambda x: x + 4),
856 ]
857
858 def extract_padding(self, p):
859 return p[: self.AceSize - 4], p[self.AceSize - 4 :]
860
861 # fmt: off
862 def toSDDL(self):
863 """
864 Return SDDL
865 """
866 sid = self.payload.Sid.summary()
867 ace_flag_string = str(
868 FlagValue(
869 self.AceFlags,
870 ["OI", "CI", "NP", "IO", "ID", "SA", "FA"]
871 )
872 )
873 ace_rights = "" # TODO
874 object_guid = "" # TODO
875 inherit_object_guid = "" # TODO
876 # ApplicationData -> conditional expression
877 condexpr = ""
878 if hasattr(self.payload, "ApplicationData"):
879 # Parse tokens
880 res = []
881 for ct in self.payload.ApplicationData.Tokens:
882 if ct.TokenType in [
883 # binary operators
884 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x88, 0x8e, 0x8f,
885 0xa0, 0xa1
886 ]:
887 t1 = res.pop(-1)
888 t0 = res.pop(-1)
889 tt = ct.sprintf("%TokenType%")
890 if ct.TokenType in [0xa0, 0xa1]: # && and ||
891 res.append(f"({t0}) {tt} ({t1})")
892 else:
893 res.append(f"{t0} {tt} {t1}")
894 elif ct.TokenType in [
895 # unary operators
896 0x87, 0x8d, 0xa2, 0x89, 0x8a, 0x8b, 0x8c, 0x91, 0x92, 0x93
897 ]:
898 t0 = res.pop(-1)
899 tt = ct.sprintf("%TokenType%")
900 res.append(f"{tt}{t0}")
901 elif ct.TokenType in [
902 # values
903 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0x50, 0x51, 0xf8, 0xf9,
904 0xfa, 0xfb
905 ]:
906 def lit(ct):
907 if ct.TokenType in [0x10, 0x18]: # literal strings
908 return '"%s"' % ct.value
909 elif ct.TokenType == 0x50: # composite
910 return "({%s})" % ",".join(lit(x) for x in ct.value)
911 else:
912 return str(ct.value)
913 res.append(lit(ct))
914 elif ct.TokenType == 0x00: # padding
915 pass
916 else:
917 raise ValueError("Unhandled token type %s" % ct.TokenType)
918 if len(res) != 1:
919 raise ValueError("Incomplete SDDL !")
920 condexpr = ";(%s)" % res[0]
921 if self.AceType in [0x9, 0xA, 0xB, 0xD]: # Conditional ACE
922 conditional_ace_type = {
923 0x09: "XA",
924 0x0A: "XD",
925 0x0B: "XU",
926 0x0D: "ZA",
927 }[self.AceType]
928 return "D:(%s)" % (
929 ";".join([
930 conditional_ace_type,
931 ace_flag_string,
932 ace_rights,
933 object_guid,
934 inherit_object_guid,
935 sid
936 ]) + condexpr
937 )
938 else:
939 ace_type = {
940 0x00: "A",
941 0x01: "D",
942 0x02: "AU",
943 0x05: "OA",
944 0x06: "OD",
945 0x07: "OU",
946 0x11: "ML",
947 0x13: "SP",
948 }[self.AceType]
949 return "(%s)" % (
950 ";".join([
951 ace_type,
952 ace_flag_string,
953 ace_rights,
954 object_guid,
955 inherit_object_guid,
956 sid
957 ]) + condexpr
958 )
959
960
961# fmt: on
962
963
964# [MS-DTYP] sect 2.4.4.2
965
966
967class WINNT_ACCESS_ALLOWED_ACE(Packet):
968 fields_desc = [
969 FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK),
970 PacketField("Sid", WINNT_SID(), WINNT_SID),
971 ]
972
973
974bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_ACE, AceType=0x00)
975
976
977# [MS-DTYP] sect 2.4.4.4
978
979
980class WINNT_ACCESS_DENIED_ACE(Packet):
981 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc
982
983
984bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_ACE, AceType=0x01)
985
986
987# [MS-DTYP] sect 2.4.4.17.4+
988
989
990class WINNT_APPLICATION_DATA_LITERAL_TOKEN(Packet):
991 def default_payload_class(self, payload):
992 return conf.padding_layer
993
994
995# fmt: off
996WINNT_APPLICATION_DATA_LITERAL_TOKEN.fields_desc = [
997 ByteEnumField(
998 "TokenType",
999 0,
1000 {
1001 # [MS-DTYP] sect 2.4.4.17.5
1002 0x00: "Padding token",
1003 0x01: "Signed int8",
1004 0x02: "Signed int16",
1005 0x03: "Signed int32",
1006 0x04: "Signed int64",
1007 0x10: "Unicode",
1008 0x18: "Octet String",
1009 0x50: "Composite",
1010 0x51: "SID",
1011 # [MS-DTYP] sect 2.4.4.17.6
1012 0x80: "==",
1013 0x81: "!=",
1014 0x82: "<",
1015 0x83: "<=",
1016 0x84: ">",
1017 0x85: ">=",
1018 0x86: "Contains",
1019 0x88: "Any_of",
1020 0x8e: "Not_Contains",
1021 0x8f: "Not_Any_of",
1022 0x89: "Member_of",
1023 0x8a: "Device_Member_of",
1024 0x8b: "Member_of_Any",
1025 0x8c: "Device_Member_of_Any",
1026 0x90: "Not_Member_of",
1027 0x91: "Not_Device_Member_of",
1028 0x92: "Not_Member_of_Any",
1029 0x93: "Not_Device_Member_of_Any",
1030 # [MS-DTYP] sect 2.4.4.17.7
1031 0x87: "Exists",
1032 0x8d: "Not_Exists",
1033 0xa0: "&&",
1034 0xa1: "||",
1035 0xa2: "!",
1036 # [MS-DTYP] sect 2.4.4.17.8
1037 0xf8: "Local attribute",
1038 0xf9: "User Attribute",
1039 0xfa: "Resource Attribute",
1040 0xfb: "Device Attribute",
1041 }
1042 ),
1043 ConditionalField(
1044 # Strings
1045 LEIntField("length", 0),
1046 lambda pkt: pkt.TokenType in [
1047 0x10, # Unicode string
1048 0x18, # Octet string
1049 0xf8, 0xf8, 0xfa, 0xfb, # Attribute tokens
1050 0x50, # Composite
1051 ]
1052 ),
1053 ConditionalField(
1054 MultipleTypeField(
1055 [
1056 (
1057 LELongField("value", 0),
1058 lambda pkt: pkt.TokenType in [
1059 0x01, # signed int8
1060 0x02, # signed int16
1061 0x03, # signed int32
1062 0x04, # signed int64
1063 ]
1064 ),
1065 (
1066 StrLenFieldUtf16("value", b"", length_from=lambda pkt: pkt.length),
1067 lambda pkt: pkt.TokenType in [
1068 0x10, # Unicode string
1069 0xf8, 0xf8, 0xfa, 0xfb, # Attribute tokens
1070 ]
1071 ),
1072 (
1073 StrLenField("value", b"", length_from=lambda pkt: pkt.length),
1074 lambda pkt: pkt.TokenType == 0x18, # Octet string
1075 ),
1076 (
1077 PacketListField("value", [], WINNT_APPLICATION_DATA_LITERAL_TOKEN,
1078 length_from=lambda pkt: pkt.length),
1079 lambda pkt: pkt.TokenType == 0x50, # Composite
1080 ),
1081
1082 ],
1083 StrFixedLenField("value", b"", length=0),
1084 ),
1085 lambda pkt: pkt.TokenType in [
1086 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0xf8, 0xf8, 0xfa, 0xfb, 0x50
1087 ]
1088 ),
1089 ConditionalField(
1090 # Literal
1091 ByteEnumField("sign", 0, {
1092 0x01: "+",
1093 0x02: "-",
1094 0x03: "None",
1095 }),
1096 lambda pkt: pkt.TokenType in [
1097 0x01, # signed int8
1098 0x02, # signed int16
1099 0x03, # signed int32
1100 0x04, # signed int64
1101 ]
1102 ),
1103 ConditionalField(
1104 # Literal
1105 ByteEnumField("base", 0, {
1106 0x01: "Octal",
1107 0x02: "Decimal",
1108 0x03: "Hexadecimal",
1109 }),
1110 lambda pkt: pkt.TokenType in [
1111 0x01, # signed int8
1112 0x02, # signed int16
1113 0x03, # signed int32
1114 0x04, # signed int64
1115 ]
1116 ),
1117]
1118# fmt: on
1119
1120
1121class WINNT_APPLICATION_DATA(Packet):
1122 fields_desc = [
1123 StrFixedLenField("Magic", b"\x61\x72\x74\x78", length=4),
1124 PacketListField(
1125 "Tokens",
1126 [],
1127 WINNT_APPLICATION_DATA_LITERAL_TOKEN,
1128 ),
1129 ]
1130
1131 def default_payload_class(self, payload):
1132 return conf.padding_layer
1133
1134
1135# [MS-DTYP] sect 2.4.4.6
1136
1137
1138class WINNT_ACCESS_ALLOWED_CALLBACK_ACE(Packet):
1139 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [
1140 PacketField(
1141 "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA
1142 ),
1143 ]
1144
1145
1146bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_ACE, AceType=0x09)
1147
1148
1149# [MS-DTYP] sect 2.4.4.6
1150
1151
1152class WINNT_ACCESS_DENIED_CALLBACK_ACE(Packet):
1153 fields_desc = WINNT_ACCESS_ALLOWED_CALLBACK_ACE.fields_desc
1154
1155
1156bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_ACE, AceType=0x0A)
1157
1158
1159# [MS-DTYP] sect 2.4.4.10
1160
1161
1162class WINNT_AUDIT_ACE(Packet):
1163 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc
1164
1165
1166bind_layers(WINNT_ACE_HEADER, WINNT_AUDIT_ACE, AceType=0x02)
1167
1168
1169# [MS-DTYP] sect 2.4.5
1170
1171
1172class WINNT_ACL(Packet):
1173 fields_desc = [
1174 ByteField("AclRevision", 2),
1175 ByteField("Sbz1", 0x00),
1176 FieldLenField(
1177 "AclSize", None, length_of="Aces", adjust=lambda _, x: x + 14, fmt="<H"
1178 ),
1179 FieldLenField("AceCount", None, count_of="Aces", fmt="<H"),
1180 ShortField("Sbz2", 0),
1181 PacketListField(
1182 "Aces",
1183 [],
1184 WINNT_ACE_HEADER,
1185 count_from=lambda pkt: pkt.AceCount,
1186 ),
1187 ]
1188
1189 def toSDDL(self):
1190 return [x.toSDDL() for x in self.Aces]
1191
1192
1193# [MS-DTYP] 2.4.6 SECURITY_DESCRIPTOR
1194
1195
1196class SECURITY_DESCRIPTOR(_NTLMPayloadPacket):
1197 OFFSET = 20
1198 _NTLM_PAYLOAD_FIELD_NAME = "Data"
1199 fields_desc = [
1200 ByteField("Revision", 0x01),
1201 ByteField("Sbz1", 0x00),
1202 FlagsField(
1203 "Control",
1204 0x00,
1205 -16,
1206 [
1207 "OwnerDefaulted",
1208 "GroupDefaulted",
1209 "DACLPresent",
1210 "DACLDefaulted",
1211 "SACLPresent",
1212 "SACLDefaulted",
1213 "DACLTrusted",
1214 "ServerSecurity",
1215 "DACLComputer",
1216 "SACLComputer",
1217 "DACLAutoInheriter",
1218 "SACLAutoInherited",
1219 "DACLProtected",
1220 "SACLProtected",
1221 "RMControlValid",
1222 "SelfRelative",
1223 ],
1224 ),
1225 LEIntField("OwnerSidOffset", 0),
1226 LEIntField("GroupSidOffset", 0),
1227 LEIntField("SaclOffset", 0),
1228 LEIntField("DaclOffset", 0),
1229 _NTLMPayloadField(
1230 "Data",
1231 OFFSET,
1232 [
1233 ConditionalField(
1234 PacketField("OwnerSid", WINNT_SID(), WINNT_SID),
1235 lambda pkt: pkt.OwnerSidOffset,
1236 ),
1237 ConditionalField(
1238 PacketField("GroupSid", WINNT_SID(), WINNT_SID),
1239 lambda pkt: pkt.GroupSidOffset,
1240 ),
1241 ConditionalField(
1242 PacketField("Sacl", WINNT_ACL(), WINNT_ACL),
1243 lambda pkt: pkt.Control.SACLPresent,
1244 ),
1245 ConditionalField(
1246 PacketField("Dacl", WINNT_ACL(), WINNT_ACL),
1247 lambda pkt: pkt.Control.DACLPresent,
1248 ),
1249 ],
1250 offset_name="Offset",
1251 ),
1252 ]
1253
1254
1255# [MS-FSCC] 2.4.2 FileAllInformation
1256
1257
1258class FileAllInformation(Packet):
1259 fields_desc = [
1260 PacketField("BasicInformation", FileBasicInformation(), FileBasicInformation),
1261 PacketField(
1262 "StandardInformation", FileStandardInformation(), FileStandardInformation
1263 ),
1264 PacketField(
1265 "InternalInformation", FileInternalInformation(), FileInternalInformation
1266 ),
1267 PacketField("EaInformation", FileEaInformation(), FileEaInformation),
1268 PacketField(
1269 "AccessInformation", FileAccessInformation(), FileAccessInformation
1270 ),
1271 PacketField(
1272 "PositionInformation", FilePositionInformation(), FilePositionInformation
1273 ),
1274 PacketField("ModeInformation", FileModeInformation(), FileModeInformation),
1275 PacketField(
1276 "AlignmentInformation", FileAlignmentInformation(), FileAlignmentInformation
1277 ),
1278 PacketField("NameInformation", FILE_NAME_INFORMATION(), FILE_NAME_INFORMATION),
1279 ]
1280
1281
1282# [MS-FSCC] 2.5.1 FileFsAttributeInformation
1283
1284
1285class FileFsAttributeInformation(Packet):
1286 fields_desc = [
1287 FlagsField(
1288 "FileSystemAttributes",
1289 0x00C706FF,
1290 -32,
1291 {
1292 0x02000000: "FILE_SUPPORTS_USN_JOURNAL",
1293 0x01000000: "FILE_SUPPORTS_OPEN_BY_FILE_ID",
1294 0x00800000: "FILE_SUPPORTS_EXTENDED_ATTRIBUTES",
1295 0x00400000: "FILE_SUPPORTS_HARD_LINKS",
1296 0x00200000: "FILE_SUPPORTS_TRANSACTIONS",
1297 0x00100000: "FILE_SEQUENTIAL_WRITE_ONCE",
1298 0x00080000: "FILE_READ_ONLY_VOLUME",
1299 0x00040000: "FILE_NAMED_STREAMS",
1300 0x00020000: "FILE_SUPPORTS_ENCRYPTION",
1301 0x00010000: "FILE_SUPPORTS_OBJECT_IDS",
1302 0x00008000: "FILE_VOLUME_IS_COMPRESSED",
1303 0x00000100: "FILE_SUPPORTS_REMOTE_STORAGE",
1304 0x00000080: "FILE_SUPPORTS_REPARSE_POINTS",
1305 0x00000040: "FILE_SUPPORTS_SPARSE_FILES",
1306 0x00000020: "FILE_VOLUME_QUOTAS",
1307 0x00000010: "FILE_FILE_COMPRESSION",
1308 0x00000008: "FILE_PERSISTENT_ACLS",
1309 0x00000004: "FILE_UNICODE_ON_DISK",
1310 0x00000002: "FILE_CASE_PRESERVED_NAMES",
1311 0x00000001: "FILE_CASE_SENSITIVE_SEARCH",
1312 0x04000000: "FILE_SUPPORT_INTEGRITY_STREAMS",
1313 0x08000000: "FILE_SUPPORTS_BLOCK_REFCOUNTING",
1314 0x10000000: "FILE_SUPPORTS_SPARSE_VDL",
1315 },
1316 ),
1317 LEIntField("MaximumComponentNameLength", 255),
1318 FieldLenField(
1319 "FileSystemNameLength", None, length_of="FileSystemName", fmt="<I"
1320 ),
1321 StrLenFieldUtf16(
1322 "FileSystemName", b"NTFS", length_from=lambda pkt: pkt.FileSystemNameLength
1323 ),
1324 ]
1325
1326
1327# [MS-FSCC] 2.5.8 FileFsSizeInformation
1328
1329
1330class FileFsSizeInformation(Packet):
1331 fields_desc = [
1332 LELongField("TotalAllocationUnits", 10485760),
1333 LELongField("AvailableAllocationUnits", 1048576),
1334 LEIntField("SectorsPerAllocationUnit", 8),
1335 LEIntField("BytesPerSector", 512),
1336 ]
1337
1338
1339# [MS-FSCC] 2.5.9 FileFsVolumeInformation
1340
1341
1342class FileFsVolumeInformation(Packet):
1343 fields_desc = [
1344 UTCTimeField(
1345 "VolumeCreationTime",
1346 None,
1347 fmt="<Q",
1348 epoch=[1601, 1, 1, 0, 0, 0],
1349 custom_scaling=1e7,
1350 ),
1351 LEIntField("VolumeSerialNumber", 0),
1352 LEIntField("VolumeLabelLength", 0),
1353 ByteField("SupportsObjects", 1),
1354 ByteField("Reserved", 0),
1355 StrNullFieldUtf16("VolumeLabel", b"C"),
1356 ]
1357
1358
1359# [MS-FSCC] 2.7.1 FILE_NOTIFY_INFORMATION
1360
1361
1362class FILE_NOTIFY_INFORMATION(Packet):
1363 fields_desc = [
1364 IntField("NextEntryOffset", 0),
1365 LEIntEnumField(
1366 "Action",
1367 0,
1368 {
1369 0x00000001: "FILE_ACTION_ADDED",
1370 0x00000002: "FILE_ACTION_REMOVED",
1371 0x00000003: "FILE_ACTION_MODIFIED",
1372 0x00000004: "FILE_ACTION_RENAMED_OLD_NAME",
1373 0x00000005: "FILE_ACTION_RENAMED_NEW_NAME",
1374 0x00000006: "FILE_ACTION_ADDED_STREAM",
1375 0x00000007: "FILE_ACTION_REMOVED_STREAM",
1376 0x00000008: "FILE_ACTION_MODIFIED_STREAM",
1377 0x00000009: "FILE_ACTION_REMOVED_BY_DELETE",
1378 0x0000000A: "FILE_ACTION_ID_NOT_TUNNELLED",
1379 0x0000000B: "FILE_ACTION_TUNNELLED_ID_COLLISION",
1380 },
1381 ),
1382 FieldLenField(
1383 "FileNameLength",
1384 None,
1385 length_of="FileName",
1386 fmt="<I",
1387 ),
1388 StrLenFieldUtf16("FileName", b"", length_from=lambda x: x.FileNameLength),
1389 StrLenField(
1390 "pad",
1391 b"",
1392 length_from=lambda x: (
1393 (x.NextEntryOffset - x.FileNameLength) if x.NextEntryOffset else 0
1394 ),
1395 ),
1396 ]
1397
1398 def default_payload_class(self, s):
1399 return conf.padding_layer
1400
1401
1402_SMB2_CONFIG = [
1403 ("BufferOffset", _NTLM_ENUM.OFFSET),
1404 ("Len", _NTLM_ENUM.LEN),
1405]
1406
1407
1408def _SMB2_post_build(self, p, pay_offset, fields):
1409 """Util function to build the offset and populate the lengths"""
1410 return _NTLM_post_build(self, p, pay_offset, fields, config=_SMB2_CONFIG)
1411
1412
1413# SMB2 sect 2.1
1414
1415
1416class DirectTCP(NBTSession):
1417 name = "Direct TCP"
1418 MAXLENGTH = 0xFFFFFF
1419 fields_desc = [ByteField("zero", 0), ThreeBytesField("LENGTH", None)]
1420
1421
1422# SMB2 sect 2.2.1.1
1423
1424
1425class SMB2_Header(Packet):
1426 name = "SMB2 Header"
1427 fields_desc = [
1428 StrFixedLenField("Start", b"\xfeSMB", 4),
1429 LEShortField("StructureSize", 64),
1430 LEShortField("CreditCharge", 0),
1431 LEIntEnumField("Status", 0, STATUS_ERREF),
1432 LEShortEnumField("Command", 0, SMB2_COM),
1433 LEShortField("CreditRequest", 0),
1434 FlagsField(
1435 "Flags",
1436 0,
1437 -32,
1438 {
1439 0x00000001: "SMB2_FLAGS_SERVER_TO_REDIR",
1440 0x00000002: "SMB2_FLAGS_ASYNC_COMMAND",
1441 0x00000004: "SMB2_FLAGS_RELATED_OPERATIONS",
1442 0x00000008: "SMB2_FLAGS_SIGNED",
1443 0x10000000: "SMB2_FLAGS_DFS_OPERATIONS",
1444 0x20000000: "SMB2_FLAGS_REPLAY_OPERATION",
1445 },
1446 ),
1447 XLEIntField("NextCommand", 0),
1448 LELongField("MID", 0), # MessageID
1449 # ASYNC
1450 ConditionalField(
1451 LELongField("AsyncId", 0), lambda pkt: pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND
1452 ),
1453 # SYNC
1454 ConditionalField(
1455 LEIntField("PID", 0), # Reserved, but PID per wireshark
1456 lambda pkt: not pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND,
1457 ),
1458 ConditionalField(
1459 LEIntField("TID", 0), # TreeID
1460 lambda pkt: not pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND,
1461 ),
1462 # COMMON
1463 LELongField("SessionId", 0),
1464 XStrFixedLenField("SecuritySignature", 0, length=16),
1465 ]
1466
1467 _SMB2_OK_RETURNCODES = (
1468 # sect 3.3.4.4
1469 (0xC0000016, 0x0001), # STATUS_MORE_PROCESSING_REQUIRED
1470 (0x80000005, 0x0008), # STATUS_BUFFER_OVERFLOW (Read)
1471 (0x80000005, 0x0010), # STATUS_BUFFER_OVERFLOW (QueryInfo)
1472 (0x80000005, 0x000B), # STATUS_BUFFER_OVERFLOW (IOCTL)
1473 (0xC000000D, 0x000B), # STATUS_INVALID_PARAMETER
1474 (0x0000010C, 0x000F), # STATUS_NOTIFY_ENUM_DIR
1475 )
1476
1477 def guess_payload_class(self, payload):
1478 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR and self.Status != 0x00000000:
1479 # Check status for responses
1480 if (self.Status, self.Command) not in SMB2_Header._SMB2_OK_RETURNCODES:
1481 return SMB2_Error_Response
1482 if self.Command == 0x0000: # Negotiate
1483 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1484 return SMB2_Negotiate_Protocol_Response
1485 return SMB2_Negotiate_Protocol_Request
1486 elif self.Command == 0x0001: # Setup
1487 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1488 return SMB2_Session_Setup_Response
1489 return SMB2_Session_Setup_Request
1490 elif self.Command == 0x0002: # Logoff
1491 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1492 return SMB2_Session_Logoff_Response
1493 return SMB2_Session_Logoff_Request
1494 elif self.Command == 0x0003: # TREE connect
1495 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1496 return SMB2_Tree_Connect_Response
1497 return SMB2_Tree_Connect_Request
1498 elif self.Command == 0x0004: # TREE disconnect
1499 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1500 return SMB2_Tree_Disconnect_Response
1501 return SMB2_Tree_Disconnect_Request
1502 elif self.Command == 0x0005: # Create
1503 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1504 return SMB2_Create_Response
1505 return SMB2_Create_Request
1506 elif self.Command == 0x0006: # Close
1507 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1508 return SMB2_Close_Response
1509 return SMB2_Close_Request
1510 elif self.Command == 0x0008: # Read
1511 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1512 return SMB2_Read_Response
1513 return SMB2_Read_Request
1514 elif self.Command == 0x0009: # Write
1515 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1516 return SMB2_Write_Response
1517 return SMB2_Write_Request
1518 elif self.Command == 0x000C: # Cancel
1519 return SMB2_Cancel_Request
1520 elif self.Command == 0x000D: # Echo
1521 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1522 return SMB2_Echo_Response
1523 return SMB2_Echo_Request
1524 elif self.Command == 0x000E: # Query directory
1525 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1526 return SMB2_Query_Directory_Response
1527 return SMB2_Query_Directory_Request
1528 elif self.Command == 0x000F: # Change Notify
1529 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1530 return SMB2_Change_Notify_Response
1531 return SMB2_Change_Notify_Request
1532 elif self.Command == 0x0010: # Query info
1533 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1534 return SMB2_Query_Info_Response
1535 return SMB2_Query_Info_Request
1536 elif self.Command == 0x0011: # Set info
1537 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1538 return SMB2_Set_Info_Response
1539 return SMB2_Set_Info_Request
1540 elif self.Command == 0x000B: # IOCTL
1541 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1542 return SMB2_IOCTL_Response
1543 return SMB2_IOCTL_Request
1544 return super(SMB2_Header, self).guess_payload_class(payload)
1545
1546 def sign(self, dialect, SigningSessionKey, SigningAlgorithmId=None, IsClient=None):
1547 # [MS-SMB2] 3.1.4.1
1548 self.SecuritySignature = b"\x00" * 16
1549 s = bytes(self)
1550 if len(s) <= 64:
1551 log_runtime.warning("Cannot sign invalid SMB packet !")
1552 return s
1553 if dialect in [0x0300, 0x0302, 0x0311]: # SMB 3
1554 if dialect == 0x0311: # SMB 3.1.1
1555 if SigningAlgorithmId is None or IsClient is None:
1556 raise Exception("SMB 3.1.1 needs a SigningAlgorithmId and IsClient")
1557 else:
1558 SigningAlgorithmId = "AES-CMAC" # AES-128-CMAC
1559 if "GMAC" in SigningAlgorithmId:
1560 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
1561
1562 aesgcm = AESGCM(SigningSessionKey)
1563 nonce = struct.pack("<Q", self.MID) + struct.pack(
1564 "<I",
1565 (0 if IsClient else 1) | (0x8000000 if self.Command == 9 else 0),
1566 )
1567 sig = aesgcm.encrypt(nonce, b"", s)
1568 elif "CMAC" in SigningAlgorithmId:
1569 from cryptography.hazmat.primitives import cmac
1570 from cryptography.hazmat.primitives.ciphers import algorithms
1571
1572 c = cmac.CMAC(algorithms.AES(SigningSessionKey))
1573 c.update(s)
1574 sig = c.finalize()
1575 elif "HMAC" in SigningAlgorithmId:
1576 from scapy.layers.tls.crypto.h_mac import Hmac_SHA256
1577
1578 sig = Hmac_SHA256(SigningSessionKey).digest(s)
1579 sig = sig[:16]
1580 else:
1581 raise ValueError("Unknown SigningAlgorithmId")
1582 elif dialect in [0x0210, 0x0202]: # SMB 2.1 or SMB 2.0.2
1583 from scapy.layers.tls.crypto.h_mac import Hmac_SHA256
1584
1585 sig = Hmac_SHA256(SigningSessionKey).digest(s)
1586 sig = sig[:16]
1587 else:
1588 log_runtime.warning("Unknown SMB Version %s ! Cannot sign." % dialect)
1589 sig = s[:-16] + b"\x00" * 16
1590 self.SecuritySignature = sig
1591 # we make sure the payload is static
1592 self.payload = conf.raw_layer(load=s[64:])
1593
1594
1595class _SMB2_Payload(Packet):
1596 def do_dissect_payload(self, s):
1597 # There can be padding between this layer and the next one
1598 if self.underlayer and isinstance(self.underlayer, SMB2_Header):
1599 if self.underlayer.NextCommand:
1600 padlen = self.underlayer.NextCommand - (64 + len(self.raw_packet_cache))
1601 if padlen:
1602 self.add_payload(s[:padlen])
1603 s = s[padlen:]
1604 super(_SMB2_Payload, self).do_dissect_payload(s)
1605
1606 def answers(self, other):
1607 return (
1608 isinstance(other, _SMB2_Payload)
1609 and self.__class__ != other.__class__
1610 and (self.Command == other.Command or self.Command == -1)
1611 )
1612
1613 def guess_payload_class(self, s):
1614 if self.underlayer and isinstance(self.underlayer, SMB2_Header):
1615 if self.underlayer.NextCommand:
1616 return SMB2_Header
1617 return super(_SMB2_Payload, self).guess_payload_class(s)
1618
1619
1620# sect 2.2.2
1621
1622
1623class SMB2_Error_Response(_SMB2_Payload):
1624 Command = -1
1625 __slots__ = ["NTStatus"] # extra info
1626 name = "SMB2 Error Response"
1627 fields_desc = [
1628 XLEShortField("StructureSize", 0x09),
1629 ByteField("ErrorContextCount", 0),
1630 ByteField("Reserved", 0),
1631 FieldLenField("ByteCount", None, fmt="<I", length_of="ErrorData"),
1632 XStrLenField("ErrorData", b"", length_from=lambda pkt: pkt.ByteCount),
1633 ]
1634
1635
1636bind_top_down(SMB2_Header, SMB2_Error_Response, Flags=1) # SMB2_FLAGS_SERVER_TO_REDIR
1637
1638# sect 2.2.2.2.2
1639
1640
1641class MOVE_DST_IPADDR(Packet):
1642 fields_desc = [
1643 # Wireshark appears to get this wrong
1644 LEIntEnumField("Type", 1, {1: "IPv4", 2: "IPv6"}),
1645 IntField("Reserved", 0),
1646 MultipleTypeField(
1647 [(IP6Field("IPAddress", None), lambda pkt: pkt.Type == 2)],
1648 IPField("IPAddress", None),
1649 ),
1650 ConditionalField(
1651 # For IPv4
1652 StrFixedLenField("Reserved2", b"", length=12),
1653 lambda pkt: pkt.Type == 1,
1654 ),
1655 ]
1656
1657 def default_payload_class(self, payload):
1658 return conf.padding_layer
1659
1660
1661class SMB2_Error_Share_Redirect_Context_Response(_NTLMPayloadPacket):
1662 name = "Share Redirect Error Context Response"
1663 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
1664 fields_desc = [
1665 XLEIntField("StructureSize", 0x30),
1666 LEIntEnumField("NotificationType", 3, {3: "SHARE_MOVE_NOTIFICATION"}),
1667 XLEIntField("ResourceNameBufferOffset", None),
1668 LEIntField("ResourceNameLen", None),
1669 ShortField("Reserved", 0),
1670 ShortEnumField("TargetType", 0, {0: "IP"}),
1671 FieldLenField("IPAddrCount", None, fmt="<I", count_of="IPAddrMoveList"),
1672 PacketListField(
1673 "IPAddrMoveList",
1674 [],
1675 MOVE_DST_IPADDR,
1676 count_from=lambda pkt: pkt.IPAddrCount,
1677 ),
1678 _NTLMPayloadField(
1679 "Buffer",
1680 lambda pkt: 24 + len(pkt.IPAddrMoveList) * 24,
1681 [
1682 StrLenFieldUtf16(
1683 "ResourceName", b"", length_from=lambda pkt: pkt.ResourceNameLen
1684 ),
1685 ],
1686 ),
1687 ]
1688
1689 def post_build(self, pkt, pay):
1690 # type: (bytes, bytes) -> bytes
1691 return (
1692 _SMB2_post_build(
1693 self,
1694 pkt,
1695 24 + len(self.IPAddrMoveList) * 24,
1696 {
1697 "ResourceName": 8,
1698 },
1699 )
1700 + pay
1701 )
1702
1703
1704# sect 2.2.2.1
1705
1706
1707class SMB2_Error_ContextResponse(Packet):
1708 fields_desc = [
1709 FieldLenField("ErrorDatalength", None, fmt="<I", length_of="ErrorContextData"),
1710 LEIntEnumField("ErrorId", 0, {0: "DEFAULT", 0x72645253: "SHARE_REDIRECT"}),
1711 MultipleTypeField(
1712 [
1713 (
1714 PacketField(
1715 "ErrorContextData",
1716 SMB2_Error_Share_Redirect_Context_Response(),
1717 SMB2_Error_Share_Redirect_Context_Response,
1718 ),
1719 lambda pkt: pkt.ErrorId == 0x72645253,
1720 )
1721 ],
1722 XStrLenField(
1723 "ErrorContextData", b"", length_from=lambda pkt: pkt.ErrorDatalength
1724 ),
1725 ),
1726 ]
1727
1728
1729# sect 2.2.3
1730
1731
1732class SMB2_Negotiate_Context(Packet):
1733 name = "SMB2 Negotiate Context"
1734 fields_desc = [
1735 LEShortEnumField("ContextType", 0x0, SMB2_NEGOTIATE_CONTEXT_TYPES),
1736 LenField("DataLength", None, fmt="<H"),
1737 IntField("Reserved", 0),
1738 ]
1739
1740 def default_payload_class(self, payload):
1741 return conf.padding_layer
1742
1743
1744class SMB2_Negotiate_Protocol_Request(_SMB2_Payload, _NTLMPayloadPacket):
1745 name = "SMB2 Negotiate Protocol Request"
1746 Command = 0x0000
1747 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
1748 fields_desc = [
1749 XLEShortField("StructureSize", 0x24),
1750 FieldLenField("DialectCount", None, fmt="<H", count_of="Dialects"),
1751 # SecurityMode
1752 FlagsField("SecurityMode", 0, -16, SMB2_SECURITY_MODE),
1753 LEShortField("Reserved", 0),
1754 # Capabilities
1755 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
1756 UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
1757 XLEIntField("NegotiateContextsBufferOffset", None),
1758 LEShortField("NegotiateContextsCount", None),
1759 ShortField("Reserved2", 0),
1760 FieldListField(
1761 "Dialects",
1762 [0x0202],
1763 LEShortEnumField("", 0x0, SMB_DIALECTS),
1764 count_from=lambda pkt: pkt.DialectCount,
1765 ),
1766 _NTLMPayloadField(
1767 "Buffer",
1768 lambda pkt: 64 + 36 + len(pkt.Dialects) * 2,
1769 [
1770 # Field only exists if Dialects contains 0x0311
1771 FieldListField(
1772 "NegotiateContexts",
1773 [],
1774 ReversePadField(
1775 PacketField("Context", None, SMB2_Negotiate_Context),
1776 8,
1777 ),
1778 count_from=lambda pkt: pkt.NegotiateContextsCount,
1779 ),
1780 ],
1781 ),
1782 ]
1783
1784 def post_build(self, pkt, pay):
1785 # type: (bytes, bytes) -> bytes
1786 return (
1787 _NTLM_post_build(
1788 self,
1789 pkt,
1790 64 + 36 + len(self.Dialects) * 2,
1791 {
1792 "NegotiateContexts": 28,
1793 },
1794 config=[
1795 ("BufferOffset", _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8),
1796 ("Count", _NTLM_ENUM.COUNT),
1797 ],
1798 )
1799 + pay
1800 )
1801
1802
1803bind_top_down(
1804 SMB2_Header,
1805 SMB2_Negotiate_Protocol_Request,
1806 Command=0x0000,
1807)
1808
1809# sect 2.2.3.1.1
1810
1811
1812class SMB2_Preauth_Integrity_Capabilities(Packet):
1813 name = "SMB2 Preauth Integrity Capabilities"
1814 fields_desc = [
1815 # According to the spec, this field value must be greater than 0
1816 # (cf Section 2.2.3.1.1 of MS-SMB2.pdf)
1817 FieldLenField("HashAlgorithmCount", None, fmt="<H", count_of="HashAlgorithms"),
1818 FieldLenField("SaltLength", None, fmt="<H", length_of="Salt"),
1819 FieldListField(
1820 "HashAlgorithms",
1821 [0x0001],
1822 LEShortEnumField(
1823 "",
1824 0x0,
1825 {
1826 # As for today, no other hash algorithm is described by the spec
1827 0x0001: "SHA-512",
1828 },
1829 ),
1830 count_from=lambda pkt: pkt.HashAlgorithmCount,
1831 ),
1832 XStrLenField("Salt", "", length_from=lambda pkt: pkt.SaltLength),
1833 ]
1834
1835 def default_payload_class(self, payload):
1836 return conf.padding_layer
1837
1838
1839bind_layers(
1840 SMB2_Negotiate_Context, SMB2_Preauth_Integrity_Capabilities, ContextType=0x0001
1841)
1842
1843# sect 2.2.3.1.2
1844
1845
1846class SMB2_Encryption_Capabilities(Packet):
1847 name = "SMB2 Encryption Capabilities"
1848 fields_desc = [
1849 # According to the spec, this field value must be greater than 0
1850 # (cf Section 2.2.3.1.2 of MS-SMB2.pdf)
1851 FieldLenField("CipherCount", None, fmt="<H", count_of="Ciphers"),
1852 FieldListField(
1853 "Ciphers",
1854 [0x0001],
1855 LEShortEnumField(
1856 "",
1857 0x0,
1858 SMB2_ENCRYPTION_CIPHERS,
1859 ),
1860 count_from=lambda pkt: pkt.CipherCount,
1861 ),
1862 ]
1863
1864 def default_payload_class(self, payload):
1865 return conf.padding_layer
1866
1867
1868bind_layers(SMB2_Negotiate_Context, SMB2_Encryption_Capabilities, ContextType=0x0002)
1869
1870# sect 2.2.3.1.3
1871
1872
1873class SMB2_Compression_Capabilities(Packet):
1874 name = "SMB2 Compression Capabilities"
1875 fields_desc = [
1876 FieldLenField(
1877 "CompressionAlgorithmCount",
1878 None,
1879 fmt="<H",
1880 count_of="CompressionAlgorithms",
1881 ),
1882 ShortField("Padding", 0x0),
1883 IntEnumField(
1884 "Flags",
1885 0x0,
1886 {
1887 0x00000000: "SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE",
1888 0x00000001: "SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED",
1889 },
1890 ),
1891 FieldListField(
1892 "CompressionAlgorithms",
1893 None,
1894 LEShortEnumField("", 0x0, SMB2_COMPRESSION_ALGORITHMS),
1895 count_from=lambda pkt: pkt.CompressionAlgorithmCount,
1896 ),
1897 ]
1898
1899 def default_payload_class(self, payload):
1900 return conf.padding_layer
1901
1902
1903bind_layers(SMB2_Negotiate_Context, SMB2_Compression_Capabilities, ContextType=0x0003)
1904
1905# sect 2.2.3.1.4
1906
1907
1908class SMB2_Netname_Negotiate_Context_ID(Packet):
1909 name = "SMB2 Netname Negotiate Context ID"
1910 fields_desc = [StrFieldUtf16("NetName", "")]
1911
1912 def default_payload_class(self, payload):
1913 return conf.padding_layer
1914
1915
1916bind_layers(
1917 SMB2_Negotiate_Context, SMB2_Netname_Negotiate_Context_ID, ContextType=0x0005
1918)
1919
1920# sect 2.2.3.1.5
1921
1922
1923class SMB2_Transport_Capabilities(Packet):
1924 name = "SMB2 Transport Capabilities"
1925 fields_desc = [
1926 FlagsField(
1927 "Flags",
1928 0x0,
1929 -32,
1930 {
1931 0x00000001: "SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY",
1932 },
1933 ),
1934 ]
1935
1936 def default_payload_class(self, payload):
1937 return conf.padding_layer
1938
1939
1940bind_layers(SMB2_Negotiate_Context, SMB2_Transport_Capabilities, ContextType=0x0006)
1941
1942# sect 2.2.3.1.6
1943
1944
1945class SMB2_RDMA_Transform_Capabilities(Packet):
1946 name = "SMB2 RDMA Transform Capabilities"
1947 fields_desc = [
1948 FieldLenField("TransformCount", None, fmt="<H", count_of="RDMATransformIds"),
1949 LEShortField("Reserved1", 0),
1950 LEIntField("Reserved2", 0),
1951 FieldListField(
1952 "RDMATransformIds",
1953 None,
1954 LEShortEnumField(
1955 "",
1956 0x0,
1957 {
1958 0x0000: "SMB2_RDMA_TRANSFORM_NONE",
1959 0x0001: "SMB2_RDMA_TRANSFORM_ENCRYPTION",
1960 0x0002: "SMB2_RDMA_TRANSFORM_SIGNING",
1961 },
1962 ),
1963 count_from=lambda pkt: pkt.TransformCount,
1964 ),
1965 ]
1966
1967 def default_payload_class(self, payload):
1968 return conf.padding_layer
1969
1970
1971bind_layers(
1972 SMB2_Negotiate_Context, SMB2_RDMA_Transform_Capabilities, ContextType=0x0007
1973)
1974
1975# sect 2.2.3.1.7
1976
1977
1978class SMB2_Signing_Capabilities(Packet):
1979 name = "SMB2 Signing Capabilities"
1980 fields_desc = [
1981 FieldLenField(
1982 "SigningAlgorithmCount", None, fmt="<H", count_of="SigningAlgorithms"
1983 ),
1984 FieldListField(
1985 "SigningAlgorithms",
1986 None,
1987 LEShortEnumField(
1988 "",
1989 0x0,
1990 SMB2_SIGNING_ALGORITHMS,
1991 ),
1992 count_from=lambda pkt: pkt.SigningAlgorithmCount,
1993 ),
1994 ]
1995
1996 def default_payload_class(self, payload):
1997 return conf.padding_layer
1998
1999
2000bind_layers(SMB2_Negotiate_Context, SMB2_Signing_Capabilities, ContextType=0x0008)
2001
2002# sect 2.2.4
2003
2004
2005class SMB2_Negotiate_Protocol_Response(_SMB2_Payload, _NTLMPayloadPacket):
2006 name = "SMB2 Negotiate Protocol Response"
2007 Command = 0x0000
2008 OFFSET = 64 + 64
2009 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2010 fields_desc = [
2011 XLEShortField("StructureSize", 0x41),
2012 FlagsField("SecurityMode", 0, -16, SMB2_SECURITY_MODE),
2013 LEShortEnumField("DialectRevision", 0x0, SMB_DIALECTS),
2014 LEShortField("NegotiateContextsCount", None),
2015 UUIDField("GUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2016 # Capabilities
2017 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
2018 LEIntField("MaxTransactionSize", 65536),
2019 LEIntField("MaxReadSize", 65536),
2020 LEIntField("MaxWriteSize", 65536),
2021 UTCTimeField(
2022 "ServerTime",
2023 None,
2024 fmt="<Q",
2025 epoch=[1601, 1, 1, 0, 0, 0],
2026 custom_scaling=1e7,
2027 ),
2028 UTCTimeField(
2029 "ServerStartTime",
2030 None,
2031 fmt="<Q",
2032 epoch=[1601, 1, 1, 0, 0, 0],
2033 custom_scaling=1e7,
2034 ),
2035 XLEShortField("SecurityBlobBufferOffset", None),
2036 LEShortField("SecurityBlobLen", None),
2037 XLEIntField("NegotiateContextsBufferOffset", None),
2038 _NTLMPayloadField(
2039 "Buffer",
2040 OFFSET,
2041 [
2042 PacketLenField(
2043 "SecurityBlob",
2044 None,
2045 GSSAPI_BLOB,
2046 length_from=lambda x: x.SecurityBlobLen,
2047 ),
2048 # Field only exists if Dialect is 0x0311
2049 FieldListField(
2050 "NegotiateContexts",
2051 [],
2052 ReversePadField(
2053 PacketField("Context", None, SMB2_Negotiate_Context),
2054 8,
2055 ),
2056 count_from=lambda pkt: pkt.NegotiateContextsCount,
2057 ),
2058 ],
2059 force_order=["SecurityBlob", "NegotiateContexts"],
2060 ),
2061 ]
2062
2063 def post_build(self, pkt, pay):
2064 # type: (bytes, bytes) -> bytes
2065 pkt = _NTLM_post_build(
2066 self,
2067 pkt,
2068 self.OFFSET,
2069 {
2070 "SecurityBlob": 56,
2071 "NegotiateContexts": 60,
2072 },
2073 config=[
2074 (
2075 "BufferOffset",
2076 {
2077 "SecurityBlob": _NTLM_ENUM.OFFSET,
2078 "NegotiateContexts": _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8,
2079 },
2080 ),
2081 ],
2082 )
2083 if getattr(self, "SecurityBlob", None):
2084 if self.SecurityBlobLen is None:
2085 pkt = pkt[:58] + struct.pack("<H", len(self.SecurityBlob)) + pkt[60:]
2086 if getattr(self, "NegotiateContexts", None):
2087 if self.NegotiateContextsCount is None:
2088 pkt = pkt[:6] + struct.pack("<H", len(self.NegotiateContexts)) + pkt[8:]
2089 return pkt + pay
2090
2091
2092bind_top_down(
2093 SMB2_Header,
2094 SMB2_Negotiate_Protocol_Response,
2095 Command=0x0000,
2096 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2097)
2098
2099# sect 2.2.5
2100
2101
2102class SMB2_Session_Setup_Request(_SMB2_Payload, _NTLMPayloadPacket):
2103 name = "SMB2 Session Setup Request"
2104 Command = 0x0001
2105 OFFSET = 24 + 64
2106 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2107 fields_desc = [
2108 XLEShortField("StructureSize", 0x19),
2109 FlagsField("Flags", 0, -8, ["SMB2_SESSION_FLAG_BINDING"]),
2110 FlagsField("SecurityMode", 0, -8, SMB2_SECURITY_MODE),
2111 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
2112 LEIntField("Channel", 0),
2113 XLEShortField("SecurityBlobBufferOffset", None),
2114 LEShortField("SecurityBlobLen", None),
2115 XLELongField("PreviousSessionId", 0),
2116 _NTLMPayloadField(
2117 "Buffer",
2118 OFFSET,
2119 [
2120 PacketField("SecurityBlob", None, GSSAPI_BLOB),
2121 ],
2122 ),
2123 ]
2124
2125 def post_build(self, pkt, pay):
2126 # type: (bytes, bytes) -> bytes
2127 return (
2128 _SMB2_post_build(
2129 self,
2130 pkt,
2131 self.OFFSET,
2132 {
2133 "SecurityBlob": 12,
2134 },
2135 )
2136 + pay
2137 )
2138
2139
2140bind_top_down(
2141 SMB2_Header,
2142 SMB2_Session_Setup_Request,
2143 Command=0x0001,
2144)
2145
2146# sect 2.2.6
2147
2148
2149class SMB2_Session_Setup_Response(_SMB2_Payload, _NTLMPayloadPacket):
2150 name = "SMB2 Session Setup Response"
2151 Command = 0x0001
2152 OFFSET = 8 + 64
2153 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2154 fields_desc = [
2155 XLEShortField("StructureSize", 0x9),
2156 FlagsField(
2157 "SessionFlags",
2158 0,
2159 -16,
2160 {
2161 0x0001: "IS_GUEST",
2162 0x0002: "IS_NULL",
2163 0x0004: "ENCRYPT_DATE",
2164 },
2165 ),
2166 XLEShortField("SecurityBufferOffset", None),
2167 LEShortField("SecurityLen", None),
2168 _NTLMPayloadField(
2169 "Buffer",
2170 OFFSET,
2171 [
2172 PacketField("Security", None, GSSAPI_BLOB),
2173 ],
2174 ),
2175 ]
2176
2177 def __getattr__(self, attr):
2178 # Ease SMB1 backward compatibility
2179 if attr == "SecurityBlob":
2180 return (
2181 super(SMB2_Session_Setup_Response, self).__getattr__("Buffer")
2182 or [(None, None)]
2183 )[0][1]
2184 return super(SMB2_Session_Setup_Response, self).__getattr__(attr)
2185
2186 def setfieldval(self, attr, val):
2187 if attr == "SecurityBlob":
2188 return super(SMB2_Session_Setup_Response, self).setfieldval(
2189 "Buffer", [("Security", val)]
2190 )
2191 return super(SMB2_Session_Setup_Response, self).setfieldval(attr, val)
2192
2193 def post_build(self, pkt, pay):
2194 # type: (bytes, bytes) -> bytes
2195 return (
2196 _SMB2_post_build(
2197 self,
2198 pkt,
2199 self.OFFSET,
2200 {
2201 "Security": 4,
2202 },
2203 )
2204 + pay
2205 )
2206
2207
2208bind_top_down(
2209 SMB2_Header,
2210 SMB2_Session_Setup_Response,
2211 Command=0x0001,
2212 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2213)
2214
2215# sect 2.2.7
2216
2217
2218class SMB2_Session_Logoff_Request(_SMB2_Payload):
2219 name = "SMB2 LOGOFF Request"
2220 Command = 0x0002
2221 fields_desc = [
2222 XLEShortField("StructureSize", 0x4),
2223 ShortField("reserved", 0),
2224 ]
2225
2226
2227bind_top_down(
2228 SMB2_Header,
2229 SMB2_Session_Logoff_Request,
2230 Command=0x0002,
2231)
2232
2233# sect 2.2.8
2234
2235
2236class SMB2_Session_Logoff_Response(_SMB2_Payload):
2237 name = "SMB2 LOGOFF Request"
2238 Command = 0x0002
2239 fields_desc = [
2240 XLEShortField("StructureSize", 0x4),
2241 ShortField("reserved", 0),
2242 ]
2243
2244
2245bind_top_down(
2246 SMB2_Header,
2247 SMB2_Session_Logoff_Response,
2248 Command=0x0002,
2249 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2250)
2251
2252# sect 2.2.9
2253
2254
2255class SMB2_Tree_Connect_Request(_SMB2_Payload, _NTLMPayloadPacket):
2256 name = "SMB2 TREE_CONNECT Request"
2257 Command = 0x0003
2258 OFFSET = 8 + 64
2259 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2260 fields_desc = [
2261 XLEShortField("StructureSize", 0x9),
2262 FlagsField(
2263 "Flags",
2264 0,
2265 -16,
2266 ["CLUSTER_RECONNECT", "REDIRECT_TO_OWNER", "EXTENSION_PRESENT"],
2267 ),
2268 XLEShortField("PathBufferOffset", None),
2269 LEShortField("PathLen", None),
2270 _NTLMPayloadField(
2271 "Buffer",
2272 OFFSET,
2273 [
2274 StrFieldUtf16("Path", b""),
2275 ],
2276 ),
2277 ]
2278
2279 def post_build(self, pkt, pay):
2280 # type: (bytes, bytes) -> bytes
2281 return (
2282 _SMB2_post_build(
2283 self,
2284 pkt,
2285 self.OFFSET,
2286 {
2287 "Path": 4,
2288 },
2289 )
2290 + pay
2291 )
2292
2293
2294bind_top_down(
2295 SMB2_Header,
2296 SMB2_Tree_Connect_Request,
2297 Command=0x0003,
2298)
2299
2300# sect 2.2.10
2301
2302
2303class SMB2_Tree_Connect_Response(_SMB2_Payload):
2304 name = "SMB2 TREE_CONNECT Response"
2305 Command = 0x0003
2306 fields_desc = [
2307 XLEShortField("StructureSize", 0x10),
2308 ByteEnumField("ShareType", 0, {0x01: "DISK", 0x02: "PIPE", 0x03: "PRINT"}),
2309 ByteField("Reserved", 0),
2310 FlagsField(
2311 "ShareFlags",
2312 0x30,
2313 -32,
2314 {
2315 0x00000010: "AUTO_CACHING",
2316 0x00000020: "VDO_CACHING",
2317 0x00000030: "NO_CACHING",
2318 0x00000001: "DFS",
2319 0x00000002: "DFS_ROOT",
2320 0x00000100: "RESTRICT_EXCLUSIVE_OPENS",
2321 0x00000200: "FORCE_SHARED_DELETE",
2322 0x00000400: "ALLOW_NAMESPACE_CACHING",
2323 0x00000800: "ACCESS_BASED_DIRECTORY_ENUM",
2324 0x00001000: "FORCE_LEVELII_OPLOCK",
2325 0x00002000: "ENABLE_HASH_V1",
2326 0x00004000: "ENABLE_HASH_V2",
2327 0x00008000: "ENCRYPT_DATA",
2328 0x00040000: "IDENTITY_REMOTING",
2329 0x00100000: "COMPRESS_DATA",
2330 },
2331 ),
2332 FlagsField(
2333 "Capabilities",
2334 0,
2335 -32,
2336 {
2337 0x00000008: "DFS",
2338 0x00000010: "CONTINUOUS_AVAILABILITY",
2339 0x00000020: "SCALEOUT",
2340 0x00000040: "CLUSTER",
2341 0x00000080: "ASYMMETRIC",
2342 0x00000100: "REDIRECT_TO_OWNER",
2343 },
2344 ),
2345 FlagsField("MaximalAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
2346 ]
2347
2348
2349bind_top_down(SMB2_Header, SMB2_Tree_Connect_Response, Command=0x0003, Flags=1)
2350
2351# sect 2.2.11
2352
2353
2354class SMB2_Tree_Disconnect_Request(_SMB2_Payload):
2355 name = "SMB2 TREE_DISCONNECT Request"
2356 Command = 0x0004
2357 fields_desc = [
2358 XLEShortField("StructureSize", 0x4),
2359 XLEShortField("Reserved", 0),
2360 ]
2361
2362
2363bind_top_down(SMB2_Header, SMB2_Tree_Disconnect_Request, Command=0x0004)
2364
2365# sect 2.2.12
2366
2367
2368class SMB2_Tree_Disconnect_Response(_SMB2_Payload):
2369 name = "SMB2 TREE_DISCONNECT Response"
2370 Command = 0x0004
2371 fields_desc = [
2372 XLEShortField("StructureSize", 0x4),
2373 XLEShortField("Reserved", 0),
2374 ]
2375
2376
2377bind_top_down(SMB2_Header, SMB2_Tree_Disconnect_Response, Command=0x0004, Flags=1)
2378
2379
2380# sect 2.2.14.1
2381
2382
2383class SMB2_FILEID(Packet):
2384 fields_desc = [XLELongField("Persistent", 0), XLELongField("Volatile", 0)]
2385
2386 def __hash__(self):
2387 return self.Persistent + self.Volatile << 64
2388
2389 def default_payload_class(self, payload):
2390 return conf.padding_layer
2391
2392
2393# sect 2.2.14.2
2394
2395
2396class SMB2_CREATE_DURABLE_HANDLE_RESPONSE(Packet):
2397 fields_desc = [
2398 XStrFixedLenField("Reserved", b"\x00" * 8, length=8),
2399 ]
2400
2401
2402class SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE(Packet):
2403 fields_desc = [
2404 LEIntEnumField("QueryStatus", 0, STATUS_ERREF),
2405 FlagsField("MaximalAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
2406 ]
2407
2408
2409class SMB2_CREATE_QUERY_ON_DISK_ID(Packet):
2410 fields_desc = [
2411 XLELongField("DiskFileId", 0),
2412 XLELongField("VolumeId", 0),
2413 XStrFixedLenField("Reserved", b"", length=16),
2414 ]
2415
2416
2417class SMB2_CREATE_RESPONSE_LEASE(Packet):
2418 fields_desc = [
2419 XStrFixedLenField("LeaseKey", b"", length=16),
2420 FlagsField(
2421 "LeaseState",
2422 0x7,
2423 -32,
2424 {
2425 0x01: "SMB2_LEASE_READ_CACHING",
2426 0x02: "SMB2_LEASE_HANDLE_CACHING",
2427 0x04: "SMB2_LEASE_WRITE_CACHING",
2428 },
2429 ),
2430 FlagsField(
2431 "LeaseFlags",
2432 0,
2433 -32,
2434 {
2435 0x02: "SMB2_LEASE_FLAG_BREAK_IN_PROGRESS",
2436 0x04: "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET",
2437 },
2438 ),
2439 LELongField("LeaseDuration", 0),
2440 ]
2441
2442
2443class SMB2_CREATE_RESPONSE_LEASE_V2(Packet):
2444 fields_desc = [
2445 SMB2_CREATE_RESPONSE_LEASE,
2446 XStrFixedLenField("ParentLeaseKey", b"", length=16),
2447 LEShortField("Epoch", 0),
2448 LEShortField("Reserved", 0),
2449 ]
2450
2451
2452class SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2(Packet):
2453 fields_desc = [
2454 LEIntField("Timeout", 0),
2455 FlagsField(
2456 "Flags",
2457 0,
2458 -32,
2459 {
2460 0x02: "SMB2_DHANDLE_FLAG_PERSISTENT",
2461 },
2462 ),
2463 ]
2464
2465
2466# sect 2.2.13
2467
2468
2469class SMB2_CREATE_DURABLE_HANDLE_REQUEST(Packet):
2470 fields_desc = [
2471 XStrFixedLenField("DurableRequest", b"", length=16),
2472 ]
2473
2474
2475class SMB2_CREATE_DURABLE_HANDLE_RECONNECT(Packet):
2476 fields_desc = [
2477 PacketField("Data", SMB2_FILEID(), SMB2_FILEID),
2478 ]
2479
2480
2481class SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST(Packet):
2482 fields_desc = [
2483 LELongField("Timestamp", 0),
2484 ]
2485
2486
2487class SMB2_CREATE_ALLOCATION_SIZE(Packet):
2488 fields_desc = [
2489 LELongField("AllocationSize", 0),
2490 ]
2491
2492
2493class SMB2_CREATE_TIMEWARP_TOKEN(Packet):
2494 fields_desc = [
2495 LELongField("Timestamp", 0),
2496 ]
2497
2498
2499class SMB2_CREATE_REQUEST_LEASE(Packet):
2500 fields_desc = [
2501 SMB2_CREATE_RESPONSE_LEASE,
2502 ]
2503
2504
2505class SMB2_CREATE_REQUEST_LEASE_V2(Packet):
2506 fields_desc = [
2507 SMB2_CREATE_RESPONSE_LEASE_V2,
2508 ]
2509
2510
2511class SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2(Packet):
2512 fields_desc = [
2513 SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2,
2514 XStrFixedLenField("Reserved", b"", length=8),
2515 UUIDField("CreateGuid", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2516 ]
2517
2518
2519class SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2(Packet):
2520 fields_desc = [
2521 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
2522 UUIDField("CreateGuid", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2523 FlagsField(
2524 "Flags",
2525 0,
2526 -32,
2527 {
2528 0x02: "SMB2_DHANDLE_FLAG_PERSISTENT",
2529 },
2530 ),
2531 ]
2532
2533
2534class SMB2_CREATE_APP_INSTANCE_ID(Packet):
2535 fields_desc = [
2536 XLEShortField("StructureSize", 0x14),
2537 LEShortField("Reserved", 0),
2538 XStrFixedLenField("AppInstanceId", b"", length=16),
2539 ]
2540
2541
2542class SMB2_CREATE_APP_INSTANCE_VERSION(Packet):
2543 fields_desc = [
2544 XLEShortField("StructureSize", 0x18),
2545 LEShortField("Reserved", 0),
2546 LEIntField("Padding", 0),
2547 LELongField("AppInstanceVersionHigh", 0),
2548 LELongField("AppInstanceVersionLow", 0),
2549 ]
2550
2551
2552class SMB2_Create_Context(_NTLMPayloadPacket):
2553 name = "SMB2 CREATE CONTEXT"
2554 OFFSET = 16
2555 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2556 fields_desc = [
2557 LEIntField("Next", None),
2558 XLEShortField("NameBufferOffset", None),
2559 LEShortField("NameLen", None),
2560 ShortField("Reserved", 0),
2561 XLEShortField("DataBufferOffset", None),
2562 LEIntField("DataLen", None),
2563 _NTLMPayloadField(
2564 "Buffer",
2565 OFFSET,
2566 [
2567 PadField(
2568 StrLenField("Name", b"", length_from=lambda pkt: pkt.NameLen),
2569 8,
2570 ),
2571 # Must be padded on 8-octet alignment
2572 PacketLenField(
2573 "Data", None, conf.raw_layer, length_from=lambda pkt: pkt.DataLen
2574 ),
2575 ],
2576 force_order=["Name", "Data"],
2577 ),
2578 StrLenField(
2579 "pad",
2580 b"",
2581 length_from=lambda x: (
2582 x.Next
2583 - max(x.DataBufferOffset + x.DataLen, x.NameBufferOffset + x.NameLen)
2584 )
2585 if x.Next
2586 else 0,
2587 ),
2588 ]
2589
2590 def post_dissect(self, s):
2591 if not self.DataLen:
2592 return s
2593 try:
2594 if isinstance(self.parent, SMB2_Create_Request):
2595 data_cls = {
2596 b"DHnQ": SMB2_CREATE_DURABLE_HANDLE_REQUEST,
2597 b"DHnC": SMB2_CREATE_DURABLE_HANDLE_RECONNECT,
2598 b"AISi": SMB2_CREATE_ALLOCATION_SIZE,
2599 b"MxAc": SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST,
2600 b"TWrp": SMB2_CREATE_TIMEWARP_TOKEN,
2601 b"QFid": SMB2_CREATE_QUERY_ON_DISK_ID,
2602 b"RqLs": SMB2_CREATE_REQUEST_LEASE,
2603 b"DH2Q": SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2,
2604 b"DH2C": SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2,
2605 # 3.1.1 only
2606 b"E\xbc\xa6j\xef\xa7\xf7J\x90\x08\xfaF.\x14Mt": SMB2_CREATE_APP_INSTANCE_ID, # noqa: E501
2607 b"\xb9\x82\xd0\xb7;V\x07O\xa0{RJ\x81\x16\xa0\x10": SMB2_CREATE_APP_INSTANCE_VERSION, # noqa: E501
2608 }[self.Name]
2609 if self.Name == b"RqLs" and self.DataLen > 32:
2610 data_cls = SMB2_CREATE_REQUEST_LEASE_V2
2611 elif isinstance(self.parent, SMB2_Create_Response):
2612 data_cls = {
2613 b"DHnQ": SMB2_CREATE_DURABLE_HANDLE_RESPONSE,
2614 b"MxAc": SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE,
2615 b"QFid": SMB2_CREATE_QUERY_ON_DISK_ID,
2616 b"RqLs": SMB2_CREATE_RESPONSE_LEASE,
2617 b"DH2Q": SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2,
2618 }[self.Name]
2619 if self.Name == b"RqLs" and self.DataLen > 32:
2620 data_cls = SMB2_CREATE_RESPONSE_LEASE_V2
2621 else:
2622 return s
2623 except KeyError:
2624 return s
2625 self.Data = data_cls(self.Data.load)
2626 return s
2627
2628 def default_payload_class(self, _):
2629 return conf.padding_layer
2630
2631 def post_build(self, pkt, pay):
2632 # type: (bytes, bytes) -> bytes
2633 return (
2634 _NTLM_post_build(
2635 self,
2636 pkt,
2637 self.OFFSET,
2638 {
2639 "Name": 4,
2640 "Data": 10,
2641 },
2642 config=[
2643 (
2644 "BufferOffset",
2645 {
2646 "Name": _NTLM_ENUM.OFFSET,
2647 "Data": _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8,
2648 },
2649 ),
2650 ("Len", _NTLM_ENUM.LEN),
2651 ],
2652 )
2653 + pay
2654 )
2655
2656
2657# sect 2.2.13
2658
2659SMB2_OPLOCK_LEVELS = {
2660 0x00: "SMB2_OPLOCK_LEVEL_NONE",
2661 0x01: "SMB2_OPLOCK_LEVEL_II",
2662 0x08: "SMB2_OPLOCK_LEVEL_EXCLUSIVE",
2663 0x09: "SMB2_OPLOCK_LEVEL_BATCH",
2664 0xFF: "SMB2_OPLOCK_LEVEL_LEASE",
2665}
2666
2667
2668class SMB2_Create_Request(_SMB2_Payload, _NTLMPayloadPacket):
2669 name = "SMB2 CREATE Request"
2670 Command = 0x0005
2671 OFFSET = 56 + 64
2672 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2673 fields_desc = [
2674 XLEShortField("StructureSize", 0x39),
2675 ByteField("ShareType", 0),
2676 ByteEnumField("RequestedOplockLevel", 0, SMB2_OPLOCK_LEVELS),
2677 LEIntEnumField(
2678 "ImpersonationLevel",
2679 0,
2680 {
2681 0x00000000: "Anonymous",
2682 0x00000001: "Identification",
2683 0x00000002: "Impersonation",
2684 0x00000003: "Delegate",
2685 },
2686 ),
2687 LELongField("SmbCreateFlags", 0),
2688 LELongField("Reserved", 0),
2689 FlagsField("DesiredAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
2690 FlagsField("FileAttributes", 0x00000080, -32, FileAttributes),
2691 FlagsField(
2692 "ShareAccess",
2693 0,
2694 -32,
2695 {
2696 0x00000001: "FILE_SHARE_READ",
2697 0x00000002: "FILE_SHARE_WRITE",
2698 0x00000004: "FILE_SHARE_DELETE",
2699 },
2700 ),
2701 LEIntEnumField(
2702 "CreateDisposition",
2703 1,
2704 {
2705 0x00000000: "FILE_SUPERSEDE",
2706 0x00000001: "FILE_OPEN",
2707 0x00000002: "FILE_CREATE",
2708 0x00000003: "FILE_OPEN_IF",
2709 0x00000004: "FILE_OVERWRITE",
2710 0x00000005: "FILE_OVERWRITE_IF",
2711 },
2712 ),
2713 FlagsField(
2714 "CreateOptions",
2715 0,
2716 -32,
2717 {
2718 0x00000001: "FILE_DIRECTORY_FILE",
2719 0x00000002: "FILE_WRITE_THROUGH",
2720 0x00000004: "FILE_SEQUENTIAL_ONLY",
2721 0x00000008: "FILE_NO_INTERMEDIATE_BUFFERING",
2722 0x00000010: "FILE_SYNCHRONOUS_IO_ALERT",
2723 0x00000020: "FILE_SYNCHRONOUS_IO_NONALERT",
2724 0x00000040: "FILE_NON_DIRECTORY_FILE",
2725 0x00000100: "FILE_COMPLETE_IF_OPLOCKED",
2726 0x00000200: "FILE_RANDOM_ACCESS",
2727 0x00001000: "FILE_DELETE_ON_CLOSE",
2728 0x00002000: "FILE_OPEN_BY_FILE_ID",
2729 0x00004000: "FILE_OPEN_FOR_BACKUP_INTENT",
2730 0x00008000: "FILE_NO_COMPRESSION",
2731 0x00000400: "FILE_OPEN_REMOTE_INSTANCE",
2732 0x00010000: "FILE_OPEN_REQUIRING_OPLOCK",
2733 0x00020000: "FILE_DISALLOW_EXCLUSIVE",
2734 0x00100000: "FILE_RESERVE_OPFILTER",
2735 0x00200000: "FILE_OPEN_REPARSE_POINT",
2736 0x00400000: "FILE_OPEN_NO_RECALL",
2737 0x00800000: "FILE_OPEN_FOR_FREE_SPACE_QUERY",
2738 },
2739 ),
2740 XLEShortField("NameBufferOffset", None),
2741 LEShortField("NameLen", None),
2742 XLEIntField("CreateContextsBufferOffset", None),
2743 LEIntField("CreateContextsLen", None),
2744 _NTLMPayloadField(
2745 "Buffer",
2746 OFFSET,
2747 [
2748 StrFieldUtf16("Name", b""),
2749 _NextPacketListField(
2750 "CreateContexts",
2751 [],
2752 SMB2_Create_Context,
2753 length_from=lambda pkt: pkt.CreateContextsLen,
2754 ),
2755 ],
2756 ),
2757 ]
2758
2759 def post_build(self, pkt, pay):
2760 # type: (bytes, bytes) -> bytes
2761 if len(pkt) == 0x38:
2762 # 'In the request, the Buffer field MUST be at least one byte in length.'
2763 pkt += b"\x00"
2764 return (
2765 _SMB2_post_build(
2766 self,
2767 pkt,
2768 self.OFFSET,
2769 {
2770 "Name": 44,
2771 "CreateContexts": 48,
2772 },
2773 )
2774 + pay
2775 )
2776
2777
2778bind_top_down(SMB2_Header, SMB2_Create_Request, Command=0x0005)
2779
2780
2781# sect 2.2.14
2782
2783
2784class SMB2_Create_Response(_SMB2_Payload, _NTLMPayloadPacket):
2785 name = "SMB2 CREATE Response"
2786 Command = 0x0005
2787 OFFSET = 88 + 64
2788 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2789 fields_desc = [
2790 XLEShortField("StructureSize", 0x59),
2791 ByteEnumField("OplockLevel", 0, SMB2_OPLOCK_LEVELS),
2792 FlagsField("Flags", 0, -8, {0x01: "SMB2_CREATE_FLAG_REPARSEPOINT"}),
2793 LEIntEnumField(
2794 "CreateAction",
2795 1,
2796 {
2797 0x00000000: "FILE_SUPERSEDED",
2798 0x00000001: "FILE_OPENED",
2799 0x00000002: "FILE_CREATED",
2800 0x00000003: "FILE_OVERWRITEN",
2801 },
2802 ),
2803 FileNetworkOpenInformation,
2804 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
2805 XLEIntField("CreateContextsBufferOffset", None),
2806 LEIntField("CreateContextsLen", None),
2807 _NTLMPayloadField(
2808 "Buffer",
2809 OFFSET,
2810 [
2811 _NextPacketListField(
2812 "CreateContexts",
2813 [],
2814 SMB2_Create_Context,
2815 length_from=lambda pkt: pkt.CreateContextsLen,
2816 ),
2817 ],
2818 ),
2819 ]
2820
2821 def post_build(self, pkt, pay):
2822 # type: (bytes, bytes) -> bytes
2823 return (
2824 _SMB2_post_build(
2825 self,
2826 pkt,
2827 self.OFFSET,
2828 {
2829 "CreateContexts": 80,
2830 },
2831 )
2832 + pay
2833 )
2834
2835
2836bind_top_down(SMB2_Header, SMB2_Create_Response, Command=0x0005, Flags=1)
2837
2838# sect 2.2.15
2839
2840
2841class SMB2_Close_Request(_SMB2_Payload):
2842 name = "SMB2 CLOSE Request"
2843 Command = 0x0006
2844 fields_desc = [
2845 XLEShortField("StructureSize", 0x18),
2846 FlagsField("Flags", 0, -16, ["SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB"]),
2847 LEIntField("Reserved", 0),
2848 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
2849 ]
2850
2851
2852bind_top_down(
2853 SMB2_Header,
2854 SMB2_Close_Request,
2855 Command=0x0006,
2856)
2857
2858# sect 2.2.16
2859
2860
2861class SMB2_Close_Response(_SMB2_Payload):
2862 name = "SMB2 CLOSE Response"
2863 Command = 0x0006
2864 FileAttributes = 0
2865 CreationTime = 0
2866 LastAccessTime = 0
2867 LastWriteTime = 0
2868 ChangeTime = 0
2869 fields_desc = [
2870 XLEShortField("StructureSize", 0x3C),
2871 FlagsField("Flags", 0, -16, ["SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB"]),
2872 LEIntField("Reserved", 0),
2873 ] + FileNetworkOpenInformation.fields_desc[:7]
2874
2875
2876bind_top_down(
2877 SMB2_Header,
2878 SMB2_Close_Response,
2879 Command=0x0006,
2880 Flags=1,
2881)
2882
2883# sect 2.2.19
2884
2885
2886class SMB2_Read_Request(_SMB2_Payload, _NTLMPayloadPacket):
2887 name = "SMB2 READ Request"
2888 Command = 0x0008
2889 OFFSET = 48 + 64
2890 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2891 fields_desc = [
2892 XLEShortField("StructureSize", 0x31),
2893 ByteField("Padding", 0x00),
2894 FlagsField(
2895 "Flags",
2896 0,
2897 -8,
2898 {
2899 0x01: "SMB2_READFLAG_READ_UNBUFFERED",
2900 0x02: "SMB2_READFLAG_REQUEST_COMPRESSED",
2901 },
2902 ),
2903 LEIntField("Length", 4280),
2904 LELongField("Offset", 0),
2905 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
2906 LEIntField("MinimumCount", 0),
2907 LEIntEnumField(
2908 "Channel",
2909 0,
2910 {
2911 0x00000000: "SMB2_CHANNEL_NONE",
2912 0x00000001: "SMB2_CHANNEL_RDMA_V1",
2913 0x00000002: "SMB2_CHANNEL_RDMA_V1_INVALIDATE",
2914 0x00000003: "SMB2_CHANNEL_RDMA_TRANSFORM",
2915 },
2916 ),
2917 LEIntField("RemainingBytes", 0),
2918 LEShortField("ReadChannelInfoBufferOffset", None),
2919 LEShortField("ReadChannelInfoLen", None),
2920 _NTLMPayloadField(
2921 "Buffer",
2922 OFFSET,
2923 [
2924 StrLenField(
2925 "ReadChannelInfo",
2926 b"",
2927 length_from=lambda pkt: pkt.ReadChannelInfoLen,
2928 )
2929 ],
2930 ),
2931 ]
2932
2933 def post_build(self, pkt, pay):
2934 # type: (bytes, bytes) -> bytes
2935 if len(pkt) == 0x30:
2936 # 'The first byte of the Buffer field MUST be set to 0.'
2937 pkt += b"\x00"
2938 return (
2939 _SMB2_post_build(
2940 self,
2941 pkt,
2942 self.OFFSET,
2943 {
2944 "ReadChannelInfo": 44,
2945 },
2946 )
2947 + pay
2948 )
2949
2950
2951bind_top_down(
2952 SMB2_Header,
2953 SMB2_Read_Request,
2954 Command=0x0008,
2955)
2956
2957# sect 2.2.20
2958
2959
2960class SMB2_Read_Response(_SMB2_Payload, _NTLMPayloadPacket):
2961 name = "SMB2 READ Response"
2962 Command = 0x0008
2963 OFFSET = 16 + 64
2964 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2965 fields_desc = [
2966 XLEShortField("StructureSize", 0x11),
2967 LEShortField("DataBufferOffset", None),
2968 LEIntField("DataLen", None),
2969 LEIntField("DataRemaining", 0),
2970 FlagsField(
2971 "Flags",
2972 0,
2973 -32,
2974 {
2975 0x01: "SMB2_READFLAG_RESPONSE_RDMA_TRANSFORM",
2976 },
2977 ),
2978 _NTLMPayloadField(
2979 "Buffer",
2980 OFFSET,
2981 [StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen)],
2982 ),
2983 ]
2984
2985 def post_build(self, pkt, pay):
2986 # type: (bytes, bytes) -> bytes
2987 return (
2988 _SMB2_post_build(
2989 self,
2990 pkt,
2991 self.OFFSET,
2992 {
2993 "Data": 2,
2994 },
2995 )
2996 + pay
2997 )
2998
2999
3000bind_top_down(
3001 SMB2_Header,
3002 SMB2_Read_Response,
3003 Command=0x0008,
3004 Flags=1,
3005)
3006
3007
3008# sect 2.2.21
3009
3010
3011class SMB2_Write_Request(_SMB2_Payload, _NTLMPayloadPacket):
3012 name = "SMB2 WRITE Request"
3013 Command = 0x0009
3014 OFFSET = 48 + 64
3015 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3016 fields_desc = [
3017 XLEShortField("StructureSize", 0x31),
3018 LEShortField("DataBufferOffset", None),
3019 LEIntField("DataLen", None),
3020 LELongField("Offset", 0),
3021 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3022 LEIntEnumField(
3023 "Channel",
3024 0,
3025 {
3026 0x00000000: "SMB2_CHANNEL_NONE",
3027 0x00000001: "SMB2_CHANNEL_RDMA_V1",
3028 0x00000002: "SMB2_CHANNEL_RDMA_V1_INVALIDATE",
3029 0x00000003: "SMB2_CHANNEL_RDMA_TRANSFORM",
3030 },
3031 ),
3032 LEIntField("RemainingBytes", 0),
3033 LEShortField("WriteChannelInfoBufferOffset", None),
3034 LEShortField("WriteChannelInfoLen", None),
3035 FlagsField(
3036 "Flags",
3037 0,
3038 -32,
3039 {
3040 0x00000001: "SMB2_WRITEFLAG_WRITE_THROUGH",
3041 0x00000002: "SMB2_WRITEFLAG_WRITE_UNBUFFERED",
3042 },
3043 ),
3044 _NTLMPayloadField(
3045 "Buffer",
3046 OFFSET,
3047 [
3048 StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen),
3049 StrLenField(
3050 "WriteChannelInfo",
3051 b"",
3052 length_from=lambda pkt: pkt.WriteChannelInfoLen,
3053 ),
3054 ],
3055 ),
3056 ]
3057
3058 def post_build(self, pkt, pay):
3059 # type: (bytes, bytes) -> bytes
3060 return (
3061 _SMB2_post_build(
3062 self,
3063 pkt,
3064 self.OFFSET,
3065 {
3066 "Data": 2,
3067 "WriteChannelInfo": 40,
3068 },
3069 )
3070 + pay
3071 )
3072
3073
3074bind_top_down(
3075 SMB2_Header,
3076 SMB2_Write_Request,
3077 Command=0x0009,
3078)
3079
3080# sect 2.2.22
3081
3082
3083class SMB2_Write_Response(_SMB2_Payload):
3084 name = "SMB2 WRITE Response"
3085 Command = 0x0009
3086 fields_desc = [
3087 XLEShortField("StructureSize", 0x11),
3088 LEShortField("Reserved", 0),
3089 LEIntField("Count", 0),
3090 LEIntField("Remaining", 0),
3091 LEShortField("WriteChannelInfoBufferOffset", 0),
3092 LEShortField("WriteChannelInfoLen", 0),
3093 ]
3094
3095
3096bind_top_down(SMB2_Header, SMB2_Write_Response, Command=0x0009, Flags=1)
3097
3098# sect 2.2.28
3099
3100
3101class SMB2_Echo_Request(_SMB2_Payload):
3102 name = "SMB2 ECHO Request"
3103 Command = 0x000D
3104 fields_desc = [
3105 XLEShortField("StructureSize", 0x4),
3106 LEShortField("Reserved", 0),
3107 ]
3108
3109
3110bind_top_down(
3111 SMB2_Header,
3112 SMB2_Echo_Request,
3113 Command=0x000D,
3114)
3115
3116# sect 2.2.29
3117
3118
3119class SMB2_Echo_Response(_SMB2_Payload):
3120 name = "SMB2 ECHO Response"
3121 Command = 0x000D
3122 fields_desc = [
3123 XLEShortField("StructureSize", 0x4),
3124 LEShortField("Reserved", 0),
3125 ]
3126
3127
3128bind_top_down(
3129 SMB2_Header,
3130 SMB2_Echo_Response,
3131 Command=0x000D,
3132 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
3133)
3134
3135# sect 2.2.30
3136
3137
3138class SMB2_Cancel_Request(_SMB2_Payload):
3139 name = "SMB2 CANCEL Request"
3140 fields_desc = [
3141 XLEShortField("StructureSize", 0x4),
3142 LEShortField("Reserved", 0),
3143 ]
3144
3145
3146bind_top_down(
3147 SMB2_Header,
3148 SMB2_Cancel_Request,
3149 Command=0x0009,
3150)
3151
3152# sect 2.2.31.4
3153
3154
3155class SMB2_IOCTL_Validate_Negotiate_Info_Request(Packet):
3156 name = "SMB2 IOCTL Validate Negotiate Info"
3157 fields_desc = (
3158 SMB2_Negotiate_Protocol_Request.fields_desc[4:6]
3159 + SMB2_Negotiate_Protocol_Request.fields_desc[1:3][::-1] # Cap/GUID
3160 + [SMB2_Negotiate_Protocol_Request.fields_desc[9]] # SecMod/DC # Dialects
3161 )
3162
3163
3164# sect 2.2.31
3165
3166
3167class _SMB2_IOCTL_Request_PacketLenField(PacketLenField):
3168 def m2i(self, pkt, m):
3169 if pkt.CtlCode == 0x00140204: # FSCTL_VALIDATE_NEGOTIATE_INFO
3170 return SMB2_IOCTL_Validate_Negotiate_Info_Request(m)
3171 elif pkt.CtlCode == 0x00060194: # FSCTL_DFS_GET_REFERRALS
3172 return SMB2_IOCTL_REQ_GET_DFS_Referral(m)
3173 elif pkt.CtlCode == 0x00094264: # FSCTL_OFFLOAD_READ
3174 return SMB2_IOCTL_OFFLOAD_READ_Request(m)
3175 return conf.raw_layer(m)
3176
3177
3178class SMB2_IOCTL_Request(_SMB2_Payload, _NTLMPayloadPacket):
3179 name = "SMB2 IOCTL Request"
3180 Command = 0x000B
3181 OFFSET = 56 + 64
3182 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3183 deprecated_fields = {
3184 "IntputCount": ("InputLen", "alias"),
3185 "OutputCount": ("OutputLen", "alias"),
3186 }
3187 fields_desc = [
3188 XLEShortField("StructureSize", 0x39),
3189 LEShortField("Reserved", 0),
3190 LEIntEnumField(
3191 "CtlCode",
3192 0,
3193 {
3194 0x00060194: "FSCTL_DFS_GET_REFERRALS",
3195 0x0011400C: "FSCTL_PIPE_PEEK",
3196 0x00110018: "FSCTL_PIPE_WAIT",
3197 0x0011C017: "FSCTL_PIPE_TRANSCEIVE",
3198 0x001440F2: "FSCTL_SRV_COPYCHUNK",
3199 0x00144064: "FSCTL_SRV_ENUMERATE_SNAPSHOTS",
3200 0x00140078: "FSCTL_SRV_REQUEST_RESUME_KEY",
3201 0x001441BB: "FSCTL_SRV_READ_HASH",
3202 0x001480F2: "FSCTL_SRV_COPYCHUNK_WRITE",
3203 0x001401D4: "FSCTL_LMR_REQUEST_RESILIENCY",
3204 0x001401FC: "FSCTL_QUERY_NETWORK_INTERFACE_INFO",
3205 0x000900A4: "FSCTL_SET_REPARSE_POINT",
3206 0x000601B0: "FSCTL_DFS_GET_REFERRALS_EX",
3207 0x00098208: "FSCTL_FILE_LEVEL_TRIM",
3208 0x00140204: "FSCTL_VALIDATE_NEGOTIATE_INFO",
3209 0x00094264: "FSCTL_OFFLOAD_READ",
3210 },
3211 ),
3212 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3213 LEIntField("InputBufferOffset", None),
3214 LEIntField("InputLen", None), # Called InputCount but it's a length
3215 LEIntField("MaxInputResponse", 0),
3216 LEIntField("OutputBufferOffset", None),
3217 LEIntField("OutputLen", None), # Called OutputCount.
3218 LEIntField("MaxOutputResponse", 1024),
3219 FlagsField("Flags", 0, -32, {0x00000001: "SMB2_0_IOCTL_IS_FSCTL"}),
3220 LEIntField("Reserved2", 0),
3221 _NTLMPayloadField(
3222 "Buffer",
3223 OFFSET,
3224 [
3225 _SMB2_IOCTL_Request_PacketLenField(
3226 "Input", None, conf.raw_layer, length_from=lambda pkt: pkt.InputLen
3227 ),
3228 _SMB2_IOCTL_Request_PacketLenField(
3229 "Output",
3230 None,
3231 conf.raw_layer,
3232 length_from=lambda pkt: pkt.OutputLen,
3233 ),
3234 ],
3235 ),
3236 ]
3237
3238 def post_build(self, pkt, pay):
3239 # type: (bytes, bytes) -> bytes
3240 return (
3241 _SMB2_post_build(
3242 self,
3243 pkt,
3244 self.OFFSET,
3245 {
3246 "Input": 24,
3247 "Output": 36,
3248 },
3249 )
3250 + pay
3251 )
3252
3253
3254bind_top_down(
3255 SMB2_Header,
3256 SMB2_IOCTL_Request,
3257 Command=0x000B,
3258)
3259
3260# sect 2.2.32.5
3261
3262
3263class SOCKADDR_STORAGE(Packet):
3264 fields_desc = [
3265 LEShortEnumField("Family", 0x0002, {0x0002: "IPv4", 0x0017: "IPv6"}),
3266 ShortField("Port", 0),
3267 # IPv4
3268 ConditionalField(
3269 IPField("IPv4Adddress", None),
3270 lambda pkt: pkt.Family == 0x0002,
3271 ),
3272 ConditionalField(
3273 StrFixedLenField("Reserved", b"", length=8),
3274 lambda pkt: pkt.Family == 0x0002,
3275 ),
3276 # IPv6
3277 ConditionalField(
3278 LEIntField("FlowInfo", 0),
3279 lambda pkt: pkt.Family == 0x00017,
3280 ),
3281 ConditionalField(
3282 IP6Field("IPv6Address", None),
3283 lambda pkt: pkt.Family == 0x00017,
3284 ),
3285 ConditionalField(
3286 LEIntField("ScopeId", 0),
3287 lambda pkt: pkt.Family == 0x00017,
3288 ),
3289 ]
3290
3291 def default_payload_class(self, _):
3292 return conf.padding_layer
3293
3294
3295class NETWORK_INTERFACE_INFO(Packet):
3296 fields_desc = [
3297 LEIntField("Next", None), # 0 = no next entry
3298 LEIntField("IfIndex", 1),
3299 FlagsField(
3300 "Capability",
3301 1,
3302 -32,
3303 {
3304 0x00000001: "RSS_CAPABLE",
3305 0x00000002: "RDMA_CAPABLE",
3306 },
3307 ),
3308 LEIntField("Reserved", 0),
3309 ScalingField("LinkSpeed", 10000000000, fmt="<Q", unit="bit/s"),
3310 PacketField("SockAddr_Storage", SOCKADDR_STORAGE(), SOCKADDR_STORAGE),
3311 ]
3312
3313 def default_payload_class(self, _):
3314 return conf.padding_layer
3315
3316
3317class SMB2_IOCTL_Network_Interface_Info(Packet):
3318 name = "SMB2 IOCTL Network Interface Info response"
3319 fields_desc = [
3320 _NextPacketListField("interfaces", [], NETWORK_INTERFACE_INFO),
3321 ]
3322
3323
3324# sect 2.2.32.6
3325
3326
3327class SMB2_IOCTL_Validate_Negotiate_Info_Response(Packet):
3328 name = "SMB2 IOCTL Validate Negotiate Info"
3329 fields_desc = (
3330 SMB2_Negotiate_Protocol_Response.fields_desc[4:6][::-1]
3331 + SMB2_Negotiate_Protocol_Response.fields_desc[ # Cap/GUID
3332 1:3
3333 ] # SecMod/DialectRevision
3334 )
3335
3336
3337# [MS-FSCC] sect 2.3.42
3338
3339
3340class SMB2_IOCTL_OFFLOAD_READ_Request(Packet):
3341 name = "SMB2 IOCTL OFFLOAD_READ Request"
3342 fields_desc = [
3343 LEIntField("StructureSize", 0x20),
3344 LEIntField("Flags", 0),
3345 LEIntField("TokenTimeToLive", 0),
3346 LEIntField("Reserved", 0),
3347 LELongField("FileOffset", 0),
3348 LELongField("CopyLength", 0),
3349 ]
3350
3351
3352# [MS-FSCC] sect 2.1.11
3353
3354
3355class STORAGE_OFFLOAD_TOKEN(Packet):
3356 fields_desc = [
3357 LEIntEnumField(
3358 "TokenType",
3359 0xFFFF0001,
3360 {
3361 0xFFFF0001: "STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA",
3362 },
3363 ),
3364 LEShortField("Reserved", 0),
3365 FieldLenField("TokenIdLength", None, fmt="<H", length_of="TokenId"),
3366 StrFixedLenField("TokenId", b"", length=504),
3367 ]
3368
3369
3370# [MS-FSCC] sect 2.3.42
3371
3372
3373class SMB2_IOCTL_OFFLOAD_READ_Response(Packet):
3374 name = "SMB2 IOCTL OFFLOAD_READ Response"
3375 fields_desc = [
3376 LEIntField("StructureSize", 0x210),
3377 FlagsField(
3378 "Flags",
3379 0,
3380 -32,
3381 {
3382 0x00000001: "OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE",
3383 },
3384 ),
3385 LELongField("TransferLength", 0),
3386 PacketField("Token", STORAGE_OFFLOAD_TOKEN(), STORAGE_OFFLOAD_TOKEN),
3387 ]
3388
3389
3390# sect 2.2.32
3391
3392
3393class _SMB2_IOCTL_Response_PacketLenField(PacketLenField):
3394 def m2i(self, pkt, m):
3395 if pkt.CtlCode == 0x00140204: # FSCTL_VALIDATE_NEGOTIATE_INFO
3396 return SMB2_IOCTL_Validate_Negotiate_Info_Response(m)
3397 elif pkt.CtlCode == 0x001401FC: # FSCTL_QUERY_NETWORK_INTERFACE_INFO
3398 return SMB2_IOCTL_Network_Interface_Info(m)
3399 elif pkt.CtlCode == 0x00060194: # FSCTL_DFS_GET_REFERRALS
3400 return SMB2_IOCTL_RESP_GET_DFS_Referral(m)
3401 return conf.raw_layer(m)
3402
3403
3404class SMB2_IOCTL_Response(_SMB2_Payload, _NTLMPayloadPacket):
3405 name = "SMB2 IOCTL Response"
3406 Command = 0x000B
3407 OFFSET = 48 + 64
3408 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3409 StructureSize = 0x31
3410 MaxOutputResponse = 0
3411 fields_desc = (
3412 SMB2_IOCTL_Request.fields_desc[:6]
3413 + SMB2_IOCTL_Request.fields_desc[7:9]
3414 + SMB2_IOCTL_Request.fields_desc[10:12]
3415 + [
3416 _NTLMPayloadField(
3417 "Buffer",
3418 OFFSET,
3419 [
3420 _SMB2_IOCTL_Response_PacketLenField(
3421 "Input",
3422 None,
3423 conf.raw_layer,
3424 length_from=lambda pkt: pkt.InputLen,
3425 ),
3426 _SMB2_IOCTL_Response_PacketLenField(
3427 "Output",
3428 None,
3429 conf.raw_layer,
3430 length_from=lambda pkt: pkt.OutputLen,
3431 ),
3432 ],
3433 ),
3434 ]
3435 )
3436
3437 def post_build(self, pkt, pay):
3438 # type: (bytes, bytes) -> bytes
3439 return (
3440 _SMB2_post_build(
3441 self,
3442 pkt,
3443 self.OFFSET,
3444 {
3445 "Input": 24,
3446 "Output": 32,
3447 },
3448 )
3449 + pay
3450 )
3451
3452
3453bind_top_down(
3454 SMB2_Header,
3455 SMB2_IOCTL_Response,
3456 Command=0x000B,
3457 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
3458)
3459
3460# sect 2.2.33
3461
3462
3463class SMB2_Query_Directory_Request(_SMB2_Payload, _NTLMPayloadPacket):
3464 name = "SMB2 QUERY DIRECTORY Request"
3465 Command = 0x000E
3466 OFFSET = 32 + 64
3467 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3468 fields_desc = [
3469 XLEShortField("StructureSize", 0x21),
3470 ByteEnumField("FileInformationClass", 0x1, FileInformationClasses),
3471 FlagsField(
3472 "Flags",
3473 0,
3474 -8,
3475 {
3476 0x01: "SMB2_RESTART_SCANS",
3477 0x02: "SMB2_RETURN_SINGLE_ENTRY",
3478 0x04: "SMB2_INDEX_SPECIFIED",
3479 0x10: "SMB2_REOPEN",
3480 },
3481 ),
3482 LEIntField("FileIndex", 0),
3483 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3484 LEShortField("FileNameBufferOffset", None),
3485 LEShortField("FileNameLen", None),
3486 LEIntField("OutputBufferLength", 65535),
3487 _NTLMPayloadField("Buffer", OFFSET, [StrFieldUtf16("FileName", b"")]),
3488 ]
3489
3490 def post_build(self, pkt, pay):
3491 # type: (bytes, bytes) -> bytes
3492 return (
3493 _SMB2_post_build(
3494 self,
3495 pkt,
3496 self.OFFSET,
3497 {
3498 "FileName": 24,
3499 },
3500 )
3501 + pay
3502 )
3503
3504
3505bind_top_down(
3506 SMB2_Header,
3507 SMB2_Query_Directory_Request,
3508 Command=0x000E,
3509)
3510
3511# sect 2.2.34
3512
3513
3514class SMB2_Query_Directory_Response(_SMB2_Payload, _NTLMPayloadPacket):
3515 name = "SMB2 QUERY DIRECTORY Response"
3516 Command = 0x000E
3517 OFFSET = 8 + 64
3518 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3519 fields_desc = [
3520 XLEShortField("StructureSize", 0x9),
3521 LEShortField("OutputBufferOffset", None),
3522 LEIntField("OutputLen", None),
3523 _NTLMPayloadField(
3524 "Buffer",
3525 OFFSET,
3526 [
3527 # TODO
3528 StrFixedLenField("Output", b"", length_from=lambda pkt: pkt.OutputLen)
3529 ],
3530 ),
3531 ]
3532
3533 def post_build(self, pkt, pay):
3534 # type: (bytes, bytes) -> bytes
3535 return (
3536 _SMB2_post_build(
3537 self,
3538 pkt,
3539 self.OFFSET,
3540 {
3541 "Output": 2,
3542 },
3543 )
3544 + pay
3545 )
3546
3547
3548bind_top_down(
3549 SMB2_Header,
3550 SMB2_Query_Directory_Response,
3551 Command=0x000E,
3552 Flags=1,
3553)
3554
3555# sect 2.2.35
3556
3557
3558class SMB2_Change_Notify_Request(_SMB2_Payload):
3559 name = "SMB2 CHANGE NOTIFY Request"
3560 Command = 0x000F
3561 fields_desc = [
3562 XLEShortField("StructureSize", 0x20),
3563 FlagsField(
3564 "Flags",
3565 0,
3566 -16,
3567 {
3568 0x0001: "SMB2_WATCH_TREE",
3569 },
3570 ),
3571 LEIntField("OutputBufferLength", 2048),
3572 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3573 FlagsField(
3574 "CompletionFilter",
3575 0,
3576 -32,
3577 {
3578 0x00000001: "FILE_NOTIFY_CHANGE_FILE_NAME",
3579 0x00000002: "FILE_NOTIFY_CHANGE_DIR_NAME",
3580 0x00000004: "FILE_NOTIFY_CHANGE_ATTRIBUTES",
3581 0x00000008: "FILE_NOTIFY_CHANGE_SIZE",
3582 0x00000010: "FILE_NOTIFY_CHANGE_LAST_WRITE",
3583 0x00000020: "FILE_NOTIFY_CHANGE_LAST_ACCESS",
3584 0x00000040: "FILE_NOTIFY_CHANGE_CREATION",
3585 0x00000080: "FILE_NOTIFY_CHANGE_EA",
3586 0x00000100: "FILE_NOTIFY_CHANGE_SECURITY",
3587 0x00000200: "FILE_NOTIFY_CHANGE_STREAM_NAME",
3588 0x00000400: "FILE_NOTIFY_CHANGE_STREAM_SIZE",
3589 0x00000800: "FILE_NOTIFY_CHANGE_STREAM_WRITE",
3590 },
3591 ),
3592 LEIntField("Reserved", 0),
3593 ]
3594
3595
3596bind_top_down(
3597 SMB2_Header,
3598 SMB2_Change_Notify_Request,
3599 Command=0x000F,
3600)
3601
3602# sect 2.2.36
3603
3604
3605class SMB2_Change_Notify_Response(_SMB2_Payload, _NTLMPayloadPacket):
3606 name = "SMB2 CHANGE NOTIFY Response"
3607 Command = 0x000F
3608 OFFSET = 8 + 64
3609 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3610 fields_desc = [
3611 XLEShortField("StructureSize", 0x9),
3612 LEShortField("OutputBufferOffset", None),
3613 LEIntField("OutputLen", None),
3614 _NTLMPayloadField(
3615 "Buffer",
3616 OFFSET,
3617 [
3618 _NextPacketListField(
3619 "Output",
3620 [],
3621 FILE_NOTIFY_INFORMATION,
3622 length_from=lambda pkt: pkt.OutputLen,
3623 max_count=1000,
3624 )
3625 ],
3626 ),
3627 ]
3628
3629 def post_build(self, pkt, pay):
3630 # type: (bytes, bytes) -> bytes
3631 return (
3632 _SMB2_post_build(
3633 self,
3634 pkt,
3635 self.OFFSET,
3636 {
3637 "Output": 2,
3638 },
3639 )
3640 + pay
3641 )
3642
3643
3644bind_top_down(
3645 SMB2_Header,
3646 SMB2_Change_Notify_Response,
3647 Command=0x000F,
3648 Flags=1,
3649)
3650
3651# sect 2.2.37
3652
3653
3654class FILE_GET_QUOTA_INFORMATION(Packet):
3655 fields_desc = [
3656 IntField("NextEntryOffset", 0),
3657 FieldLenField("SidLength", None, length_of="Sid"),
3658 StrLenField("Sid", b"", length_from=lambda x: x.SidLength),
3659 StrLenField(
3660 "pad",
3661 b"",
3662 length_from=lambda x: (
3663 (x.NextEntryOffset - x.SidLength) if x.NextEntryOffset else 0
3664 ),
3665 ),
3666 ]
3667
3668
3669class SMB2_Query_Quota_Info(Packet):
3670 fields_desc = [
3671 ByteField("ReturnSingle", 0),
3672 ByteField("ReturnBoolean", 0),
3673 ShortField("Reserved", 0),
3674 LEIntField("SidListLength", 0),
3675 LEIntField("StartSidLength", 0),
3676 LEIntField("StartSidOffset", 0),
3677 StrLenField("pad", b"", length_from=lambda x: x.StartSidOffset),
3678 MultipleTypeField(
3679 [
3680 (
3681 PacketListField(
3682 "SidBuffer",
3683 [],
3684 FILE_GET_QUOTA_INFORMATION,
3685 length_from=lambda x: x.SidListLength,
3686 ),
3687 lambda x: x.SidListLength,
3688 ),
3689 (
3690 StrLenField(
3691 "SidBuffer", b"", length_from=lambda x: x.StartSidLength
3692 ),
3693 lambda x: x.StartSidLength,
3694 ),
3695 ],
3696 StrFixedLenField("SidBuffer", b"", length=0),
3697 ),
3698 ]
3699
3700
3701SMB2_INFO_TYPE = {
3702 0x01: "SMB2_0_INFO_FILE",
3703 0x02: "SMB2_0_INFO_FILESYSTEM",
3704 0x03: "SMB2_0_INFO_SECURITY",
3705 0x04: "SMB2_0_INFO_QUOTA",
3706}
3707
3708SMB2_ADDITIONAL_INFORMATION = {
3709 0x00000001: "OWNER_SECURITY_INFORMATION",
3710 0x00000002: "GROUP_SECURITY_INFORMATION",
3711 0x00000004: "DACL_SECURITY_INFORMATION",
3712 0x00000008: "SACL_SECURITY_INFORMATION",
3713 0x00000010: "LABEL_SECURITY_INFORMATION",
3714 0x00000020: "ATTRIBUTE_SECURITY_INFORMATION",
3715 0x00000040: "SCOPE_SECURITY_INFORMATION",
3716 0x00010000: "BACKUP_SECURITY_INFORMATION",
3717}
3718
3719
3720class SMB2_Query_Info_Request(_SMB2_Payload, _NTLMPayloadPacket):
3721 name = "SMB2 QUERY INFO Request"
3722 Command = 0x0010
3723 OFFSET = 40 + 64
3724 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3725 fields_desc = [
3726 XLEShortField("StructureSize", 0x29),
3727 ByteEnumField(
3728 "InfoType",
3729 0,
3730 SMB2_INFO_TYPE,
3731 ),
3732 ByteEnumField("FileInfoClass", 0, FileInformationClasses),
3733 LEIntField("OutputBufferLength", 0),
3734 XLEIntField("InputBufferOffset", None), # Short + Reserved = Int
3735 LEIntField("InputLen", None),
3736 FlagsField(
3737 "AdditionalInformation",
3738 0,
3739 -32,
3740 SMB2_ADDITIONAL_INFORMATION,
3741 ),
3742 FlagsField(
3743 "Flags",
3744 0,
3745 -32,
3746 {
3747 0x00000001: "SL_RESTART_SCAN",
3748 0x00000002: "SL_RETURN_SINGLE_ENTRY",
3749 0x00000004: "SL_INDEX_SPECIFIED",
3750 },
3751 ),
3752 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3753 _NTLMPayloadField(
3754 "Buffer",
3755 OFFSET,
3756 [
3757 MultipleTypeField(
3758 [
3759 (
3760 # QUOTA
3761 PacketListField(
3762 "Input",
3763 None,
3764 SMB2_Query_Quota_Info,
3765 length_from=lambda pkt: pkt.InputLen,
3766 ),
3767 lambda pkt: pkt.InfoType == 0x04,
3768 ),
3769 ],
3770 StrLenField("Input", b"", length_from=lambda pkt: pkt.InputLen),
3771 ),
3772 ],
3773 ),
3774 ]
3775
3776 def post_build(self, pkt, pay):
3777 # type: (bytes, bytes) -> bytes
3778 return (
3779 _SMB2_post_build(
3780 self,
3781 pkt,
3782 self.OFFSET,
3783 {
3784 "Input": 4,
3785 },
3786 )
3787 + pay
3788 )
3789
3790
3791bind_top_down(
3792 SMB2_Header,
3793 SMB2_Query_Info_Request,
3794 Command=0x00010,
3795)
3796
3797
3798class SMB2_Query_Info_Response(_SMB2_Payload, _NTLMPayloadPacket):
3799 name = "SMB2 QUERY INFO Response"
3800 Command = 0x0010
3801 OFFSET = 8 + 64
3802 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3803 fields_desc = [
3804 XLEShortField("StructureSize", 0x9),
3805 LEShortField("OutputBufferOffset", None),
3806 LEIntField("OutputLen", None),
3807 _NTLMPayloadField(
3808 "Buffer",
3809 OFFSET,
3810 [
3811 # TODO
3812 StrFixedLenField("Output", b"", length_from=lambda pkt: pkt.OutputLen)
3813 ],
3814 ),
3815 ]
3816
3817 def post_build(self, pkt, pay):
3818 # type: (bytes, bytes) -> bytes
3819 return (
3820 _SMB2_post_build(
3821 self,
3822 pkt,
3823 self.OFFSET,
3824 {
3825 "Output": 2,
3826 },
3827 )
3828 + pay
3829 )
3830
3831
3832bind_top_down(
3833 SMB2_Header,
3834 SMB2_Query_Info_Response,
3835 Command=0x00010,
3836 Flags=1,
3837)
3838
3839
3840# sect 2.2.39
3841
3842
3843class SMB2_Set_Info_Request(_SMB2_Payload, _NTLMPayloadPacket):
3844 name = "SMB2 SET INFO Request"
3845 Command = 0x0011
3846 OFFSET = 32 + 64
3847 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3848 fields_desc = [
3849 XLEShortField("StructureSize", 0x21),
3850 ByteEnumField(
3851 "InfoType",
3852 0,
3853 SMB2_INFO_TYPE,
3854 ),
3855 ByteEnumField("FileInfoClass", 0, FileInformationClasses),
3856 LEIntField("DataLen", None),
3857 XLEIntField("DataBufferOffset", None), # Short + Reserved = Int
3858 FlagsField(
3859 "AdditionalInformation",
3860 0,
3861 -32,
3862 SMB2_ADDITIONAL_INFORMATION,
3863 ),
3864 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3865 _NTLMPayloadField(
3866 "Buffer",
3867 OFFSET,
3868 [
3869 MultipleTypeField(
3870 [
3871 (
3872 # FILE
3873 PacketLenField(
3874 "Data",
3875 None,
3876 lambda x, _parent: _FileInformationClasses.get(
3877 _parent.FileInfoClass, conf.raw_layer
3878 )(x),
3879 length_from=lambda pkt: pkt.DataLen,
3880 ),
3881 lambda pkt: pkt.InfoType == 0x01,
3882 ),
3883 (
3884 # QUOTA
3885 PacketListField(
3886 "Data",
3887 None,
3888 SMB2_Query_Quota_Info,
3889 length_from=lambda pkt: pkt.DataLen,
3890 ),
3891 lambda pkt: pkt.InfoType == 0x04,
3892 ),
3893 ],
3894 StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen),
3895 ),
3896 ],
3897 ),
3898 ]
3899
3900 def post_build(self, pkt, pay):
3901 # type: (bytes, bytes) -> bytes
3902 return (
3903 _SMB2_post_build(
3904 self,
3905 pkt,
3906 self.OFFSET,
3907 {
3908 "Data": 4,
3909 },
3910 )
3911 + pay
3912 )
3913
3914
3915bind_top_down(
3916 SMB2_Header,
3917 SMB2_Set_Info_Request,
3918 Command=0x00011,
3919)
3920
3921
3922class SMB2_Set_Info_Response(_SMB2_Payload):
3923 name = "SMB2 SET INFO Request"
3924 Command = 0x0011
3925 fields_desc = [
3926 XLEShortField("StructureSize", 0x02),
3927 ]
3928
3929
3930bind_top_down(
3931 SMB2_Header,
3932 SMB2_Set_Info_Response,
3933 Command=0x00011,
3934 Flags=1,
3935)
3936
3937
3938# sect 2.2.42.1
3939
3940
3941class SMB2_Compression_Transform_Header(Packet):
3942 name = "SMB2 Compression Transform Header"
3943 fields_desc = [
3944 StrFixedLenField("Start", b"\xfcSMB", 4),
3945 LEIntField("OriginalCompressedSegmentSize", 0x0),
3946 LEShortEnumField("CompressionAlgorithm", 0, SMB2_COMPRESSION_ALGORITHMS),
3947 ShortEnumField(
3948 "Flags",
3949 0x0,
3950 {
3951 0x0000: "SMB2_COMPRESSION_FLAG_NONE",
3952 0x0001: "SMB2_COMPRESSION_FLAG_CHAINED",
3953 },
3954 ),
3955 XLEIntField("Offset_or_Length", 0),
3956 ]
3957
3958
3959# [MS-DFSC] sect 2.2
3960
3961
3962class SMB2_IOCTL_REQ_GET_DFS_Referral(Packet):
3963 fields_desc = [
3964 LEShortField("MaxReferralLevel", 0),
3965 StrNullFieldUtf16("RequestFileName", ""),
3966 ]
3967
3968
3969class DFS_REFERRAL(Packet):
3970 fields_desc = [
3971 LEShortField("Version", 1),
3972 FieldLenField(
3973 "Size", None, fmt="<H", length_of="ShareName", adjust=lambda pkt, x: x + 9
3974 ),
3975 LEShortEnumField("ServerType", 0, {0: "non-root", 1: "root"}),
3976 LEShortField("ReferralEntryFlags", 0),
3977 StrNullFieldUtf16("ShareName", ""),
3978 ]
3979
3980 @classmethod
3981 def dispatch_hook(cls, _pkt=None, *args, **kargs):
3982 if _pkt and len(_pkt) >= 2:
3983 version = struct.unpack("<H", _pkt[:2])[0]
3984 if version == 1:
3985 return DFS_REFERRAL
3986 elif version == 3:
3987 return DFS_REFERRAL_V3
3988 elif version == 4:
3989 return DFS_REFERRAL_V4
3990 return cls
3991
3992 def default_payload_class(self, s):
3993 return conf.padding_layer
3994
3995
3996class DFS_REFERRAL_V3(DFS_REFERRAL):
3997 fields_desc = [
3998 LEShortField("Version", 3),
3999 LEShortField("Size", None),
4000 LEShortEnumField("ServerType", 0, {0: "non-root", 1: "root"}),
4001 FlagsField(
4002 "ReferralEntryFlags",
4003 0,
4004 -16,
4005 {
4006 0x0002: "NameListReferral",
4007 0x0004: "TargetSetBoundary",
4008 },
4009 ),
4010 LEIntField("TimeToLive", 300),
4011 # NameListReferral is 0
4012 ConditionalField(
4013 LEShortField("DFSPathOffset", None),
4014 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4015 ),
4016 ConditionalField(
4017 LEShortField("DFSAlternatePathOffset", None),
4018 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4019 ),
4020 ConditionalField(
4021 LEShortField("NetworkAddressOffset", None),
4022 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4023 ),
4024 ConditionalField(
4025 StrFixedLenField("ServiceSiteGuid", 0, length=16),
4026 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4027 ),
4028 # NameListReferral is 1
4029 ConditionalField(
4030 LEShortField("SpecialNameOffset", None),
4031 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4032 ),
4033 ConditionalField(
4034 LEShortField("NumberOfExpandedNames", None),
4035 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4036 ),
4037 ConditionalField(
4038 LEShortField("ExpandedNameOffset", None),
4039 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4040 ),
4041 ConditionalField(
4042 StrLenField("Padding", None, length_from=lambda pkt: pkt.Size - 18),
4043 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4044 ),
4045 ]
4046
4047 def post_build(self, pkt, pay):
4048 # type: (bytes, bytes) -> bytes
4049 if self.Size is None:
4050 pkt = pkt[:2] + struct.pack("<H", len(pkt)) + pkt[4:]
4051 return pkt + pay
4052
4053
4054class DFS_REFERRAL_V4(DFS_REFERRAL_V3):
4055 Version = 4
4056
4057
4058class DFS_REFERRAL_ENTRY0(Packet):
4059 fields_desc = [
4060 StrNullFieldUtf16("DFSPath", ""),
4061 StrNullFieldUtf16("DFSAlternatePath", ""),
4062 StrNullFieldUtf16("NetworkAddress", ""),
4063 ]
4064
4065
4066class DFS_REFERRAL_ENTRY1(Packet):
4067 fields_desc = [
4068 StrNullFieldUtf16("SpecialName", ""),
4069 FieldListField(
4070 "ExpandedName",
4071 [],
4072 StrNullFieldUtf16("", ""),
4073 ),
4074 ]
4075
4076
4077class _DFS_Referrals_BufferField(PacketListField):
4078 def getfield(self, pkt, s):
4079 results = []
4080 offset = sum(x.Size for x in pkt.ReferralEntries)
4081 for ref in pkt.ReferralEntries:
4082 # For every ref
4083 if not ref.ReferralEntryFlags.NameListReferral:
4084 cls = DFS_REFERRAL_ENTRY0
4085 else:
4086 cls = DFS_REFERRAL_ENTRY1
4087 # Build the fields manually
4088 fld = _NTLMPayloadField(
4089 "",
4090 offset,
4091 cls.fields_desc,
4092 force_order=[x.name for x in cls.fields_desc],
4093 offset_name="Offset",
4094 )
4095 remain, vals = fld.getfield(ref, s)
4096 vals = fld.i2h(ref, vals)
4097 # Append the entry class
4098 results.append(cls(**{x[0]: x[1] for x in vals}))
4099 offset -= ref.Size
4100 return b"", results
4101
4102 def addfield(self, pkt, s, vals):
4103 offset = sum(len(x) for x in pkt.ReferralEntries)
4104 for i, val in enumerate(vals):
4105 try:
4106 ref = pkt.ReferralEntries[i]
4107 except KeyError:
4108 ref = None
4109 fld = _NTLMPayloadField(
4110 "",
4111 offset,
4112 val.fields_desc,
4113 force_order=[x.name for x in val.fields_desc],
4114 offset_name="Offset",
4115 )
4116 # Append the bytes manually
4117 values = [(fld.name, getattr(val, fld.name)) for fld in val.fields_desc]
4118 values = fld.h2i(ref, values)
4119 s += fld.addfield(ref, b"", values)
4120 offset -= len(ref)
4121 return s
4122
4123
4124class SMB2_IOCTL_RESP_GET_DFS_Referral(Packet):
4125 fields_desc = [
4126 LEShortField("PathConsumed", 0),
4127 FieldLenField("NumberOfReferrals", None, fmt="<H", count_of="ReferralEntries"),
4128 FlagsField(
4129 "ReferralHeaderFlags",
4130 0,
4131 -32,
4132 {
4133 0x00000001: "ReferralServers",
4134 0x00000002: "StorageServers",
4135 0x00000004: "TargetFailback",
4136 },
4137 ),
4138 PacketListField(
4139 "ReferralEntries",
4140 [],
4141 DFS_REFERRAL,
4142 count_from=lambda pkt: pkt.NumberOfReferrals,
4143 ),
4144 _DFS_Referrals_BufferField("ReferralBuffer", []),
4145 ]
4146
4147 def post_build(self, pkt, pay):
4148 # type: (bytes, bytes) -> bytes
4149 # Note: Windows is smart and uses some sort of compression in the sense
4150 # that it re-uses fields that are used several times across ReferralBuffer.
4151 # But we just do the dumb thing because it's 'easier', and do no compression.
4152 offsets = {
4153 # DFS_REFERRAL_ENTRY0
4154 "DFSPath": 12,
4155 "DFSAlternatePath": 14,
4156 "NetworkAddress": 16,
4157 # DFS_REFERRAL_ENTRY1
4158 "SpecialName": 12,
4159 "ExpandedName": 16,
4160 }
4161 # dataoffset = pointer in the ReferralBuffer
4162 # entryoffset = pointer in the ReferralEntries
4163 dataoffset = sum(len(x) for x in self.ReferralEntries)
4164 entryoffset = 8
4165 for ref, buf in zip(self.ReferralEntries, self.ReferralBuffer):
4166 for fld in buf.fields_desc:
4167 off = entryoffset + offsets[fld.name]
4168 if ref.getfieldval(fld.name + "Offset") is None and buf.getfieldval(
4169 fld.name
4170 ):
4171 pkt = pkt[:off] + struct.pack("<H", dataoffset) + pkt[off + 2 :]
4172 dataoffset += len(fld.addfield(self, b"", buf.getfieldval(fld.name)))
4173 dataoffset -= len(ref)
4174 entryoffset += len(ref)
4175 return pkt + pay
4176
4177
4178# [MS-SMB2] various usages
4179
4180
4181def SMB2computePreauthIntegrityHashValue(
4182 PreauthIntegrityHashValue, s, HashId="SHA-512"
4183):
4184 """
4185 Update the PreauthIntegrityHashValue
4186 """
4187 # get hasher
4188 hasher = {"SHA-512": hashlib.sha512}[HashId]
4189 # compute the hash of concatenation of previous and bytes
4190 return hasher(PreauthIntegrityHashValue + s).digest()
4191
4192
4193# SMB2 socket and session
4194
4195
4196class SMBStreamSocket(StreamSocket):
4197 """
4198 A modified StreamSocket to dissect SMB compounded requests
4199 [MS-SMB2] 3.3.5.2.7
4200 """
4201
4202 def __init__(self, *args, **kwargs):
4203 self.queue = collections.deque()
4204 self.session = SMBSession()
4205 super(SMBStreamSocket, self).__init__(*args, **kwargs)
4206
4207 def recv(self, x=None):
4208 # note: normal StreamSocket takes care of NBTSession / DirectTCP fragments.
4209 # this takes care of splitting compounded requests
4210 if self.queue:
4211 return self.queue.popleft()
4212 pkt = super(SMBStreamSocket, self).recv(x)
4213 if pkt is not None and SMB2_Header in pkt:
4214 pay = pkt[SMB2_Header].payload
4215 while SMB2_Header in pay:
4216 pay = pay[SMB2_Header]
4217 pay.underlayer.remove_payload()
4218 self.queue.append(pay)
4219 if not pay.NextCommand:
4220 break
4221 pay = pay.payload
4222 return self.session.in_pkt(pkt)
4223
4224 def send(self, x, Compounded=False, **kwargs):
4225 for pkt in self.session.out_pkt(x, Compounded=Compounded):
4226 return super(SMBStreamSocket, self).send(pkt, **kwargs)
4227
4228 @staticmethod
4229 def select(sockets, remain=conf.recv_poll_rate):
4230 if any(getattr(x, "queue", None) for x in sockets):
4231 return [x for x in sockets if isinstance(x, SMBStreamSocket) and x.queue]
4232 return StreamSocket.select(sockets, remain=remain)
4233
4234
4235class SMBSession(DefaultSession):
4236 """
4237 A SMB session within a TCP socket.
4238 """
4239
4240 def __init__(self, *args, **kwargs):
4241 self.smb_header = None
4242 self.ssp = kwargs.pop("ssp", None)
4243 self.sspcontext = kwargs.pop("sspcontext", None)
4244 self.sniffsspcontexts = {} # Unfinished contexts for passive
4245 # SMB session parameters
4246 self.CompoundQueue = []
4247 self.Dialect = 0x0202 # Updated by parent
4248 self.SecurityMode = 0
4249 # Crypto parameters
4250 self.SMBSessionKey = None
4251 self.PreauthIntegrityHashId = "SHA-512"
4252 self.CipherId = "AES-128-CCM"
4253 self.SigningAlgorithmId = "AES-CMAC"
4254 self.Salt = os.urandom(32)
4255 self.ConnectionPreauthIntegrityHashValue = None
4256 self.SessionPreauthIntegrityHashValue = None
4257 # SMB 3.1.1
4258 self.SessionPreauthIntegrityHashValue = None
4259 if conf.winssps_passive:
4260 for ssp in conf.winssps_passive:
4261 self.sniffsspcontexts[ssp] = None
4262 super(SMBSession, self).__init__(*args, **kwargs)
4263
4264 # SMB crypto functions
4265
4266 @crypto_validator
4267 def computeSMBSessionKey(self):
4268 if not getattr(self.sspcontext, "SessionKey", None):
4269 # no signing key, no session key
4270 return
4271 # [MS-SMB2] sect 3.3.5.5.3
4272 if self.Dialect >= 0x0300:
4273 if self.Dialect == 0x0311:
4274 label = b"SMBSigningKey\x00"
4275 preauth_hash = self.SessionPreauthIntegrityHashValue
4276 else:
4277 label = b"SMB2AESCMAC\x00"
4278 preauth_hash = b"SmbSign\x00"
4279 # [MS-SMB2] sect 3.1.4.2
4280 if "256" in self.CipherId:
4281 L = 256
4282 elif "128" in self.CipherId:
4283 L = 128
4284 else:
4285 raise ValueError
4286 self.SMBSessionKey = SP800108_KDFCTR(
4287 self.sspcontext.SessionKey[:16],
4288 label, # label
4289 preauth_hash, # context
4290 L,
4291 )
4292 elif self.Dialect <= 0x0210:
4293 self.SMBSessionKey = self.sspcontext.SessionKey[:16]
4294 else:
4295 raise ValueError("Hmmm ? >:(")
4296
4297 def computeSMBConnectionPreauth(self, *negopkts):
4298 if self.Dialect and self.Dialect >= 0x0311: # SMB 3.1.1 only
4299 # [MS-SMB2] 3.3.5.4
4300 # TODO: handle SMB2_SESSION_FLAG_BINDING
4301 if self.ConnectionPreauthIntegrityHashValue is None:
4302 # New auth or failure
4303 self.ConnectionPreauthIntegrityHashValue = b"\x00" * 64
4304 # Calculate the *Connection* PreauthIntegrityHashValue
4305 for negopkt in negopkts:
4306 self.ConnectionPreauthIntegrityHashValue = (
4307 SMB2computePreauthIntegrityHashValue(
4308 self.ConnectionPreauthIntegrityHashValue,
4309 negopkt,
4310 HashId=self.PreauthIntegrityHashId,
4311 )
4312 )
4313
4314 def computeSMBSessionPreauth(self, *sesspkts):
4315 if self.Dialect and self.Dialect >= 0x0311: # SMB 3.1.1 only
4316 # [MS-SMB2] 3.3.5.5.3
4317 if self.SessionPreauthIntegrityHashValue is None:
4318 # New auth or failure
4319 self.SessionPreauthIntegrityHashValue = (
4320 self.ConnectionPreauthIntegrityHashValue
4321 )
4322 # Calculate the *Session* PreauthIntegrityHashValue
4323 for sesspkt in sesspkts:
4324 self.SessionPreauthIntegrityHashValue = (
4325 SMB2computePreauthIntegrityHashValue(
4326 self.SessionPreauthIntegrityHashValue,
4327 sesspkt,
4328 HashId=self.PreauthIntegrityHashId,
4329 )
4330 )
4331
4332 # I/O
4333
4334 def in_pkt(self, pkt):
4335 """
4336 Incoming SMB packet
4337 """
4338 return pkt
4339
4340 def out_pkt(self, pkt, Compounded=False):
4341 """
4342 Outgoing SMB packet
4343
4344 :param pkt: the packet to send
4345 :param Compound: if True, will be stack to be send with the next
4346 un-compounded packet
4347
4348 Handles:
4349 - handle compounded requests (if any): [MS-SMB2] 3.3.5.2.7
4350 - handles signing (if required)
4351 """
4352 # Note: impacket and wireshark get crazy on compounded+signature, but
4353 # windows+samba tells we're right :D
4354 if SMB2_Header in pkt:
4355 if self.CompoundQueue:
4356 # this is a subsequent compound: only keep the SMB2
4357 pkt = pkt[SMB2_Header]
4358 if Compounded:
4359 # [MS-SMB2] 3.2.4.1.4
4360 # "Compounded requests MUST be aligned on 8-byte boundaries; the
4361 # last request of the compounded requests does not need to be padded to
4362 # an 8-byte boundary."
4363 # [MS-SMB2] 3.1.4.1
4364 # "If the message is part of a compounded chain, any
4365 # padding at the end of the message MUST be used in the hash
4366 # computation."
4367 length = len(pkt[SMB2_Header])
4368 padlen = (-length) % 8
4369 if padlen:
4370 pkt.add_payload(b"\x00" * padlen)
4371 pkt[SMB2_Header].NextCommand = length + padlen
4372 if self.Dialect and self.SMBSessionKey and self.SecurityMode != 0:
4373 # Sign SMB2 !
4374 smb = pkt[SMB2_Header]
4375 smb.Flags += "SMB2_FLAGS_SIGNED"
4376 smb.sign(
4377 self.Dialect,
4378 self.SMBSessionKey,
4379 # SMB 3.1.1 parameters:
4380 SigningAlgorithmId=self.SigningAlgorithmId,
4381 IsClient=False,
4382 )
4383 if Compounded:
4384 # There IS a next compound. Store in queue
4385 self.CompoundQueue.append(pkt)
4386 return []
4387 else:
4388 # If there are any compounded responses in store, sum them
4389 if self.CompoundQueue:
4390 pkt = functools.reduce(lambda x, y: x / y, self.CompoundQueue) / pkt
4391 self.CompoundQueue.clear()
4392 return [pkt]
4393
4394 def process(self, pkt: Packet):
4395 # Called when passively sniffing
4396 pkt = super(SMBSession, self).process(pkt)
4397 if pkt is not None and SMB2_Header in pkt:
4398 return self.in_pkt(pkt)
4399 return pkt