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