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