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 # Total size including header:
1509 # AclRevision(1) + Sbz1(1) + AclSize(2) + AceCount(2) + Sbz2(2)
1510 FieldLenField(
1511 "AclSize",
1512 None,
1513 length_of="Aces",
1514 adjust=lambda _, x: x + 8,
1515 fmt="<H",
1516 ),
1517 FieldLenField("AceCount", None, count_of="Aces", fmt="<H"),
1518 ShortField("Sbz2", 0),
1519 PacketListField(
1520 "Aces",
1521 [],
1522 WINNT_ACE_HEADER,
1523 count_from=lambda pkt: pkt.AceCount,
1524 ),
1525 ]
1526
1527 def toSDDL(self):
1528 return [x.toSDDL() for x in self.Aces]
1529
1530
1531# [MS-DTYP] 2.4.6 SECURITY_DESCRIPTOR
1532
1533
1534class SECURITY_DESCRIPTOR(_NTLMPayloadPacket):
1535 OFFSET = 20
1536 _NTLM_PAYLOAD_FIELD_NAME = "Data"
1537 fields_desc = [
1538 ByteField("Revision", 0x01),
1539 ByteField("Sbz1", 0x00),
1540 FlagsField(
1541 "Control",
1542 0x00,
1543 -16,
1544 [
1545 "OWNER_DEFAULTED",
1546 "GROUP_DEFAULTED",
1547 "DACL_PRESENT",
1548 "DACL_DEFAULTED",
1549 "SACL_PRESENT",
1550 "SACL_DEFAULTED",
1551 "DACL_TRUSTED",
1552 "SERVER_SECURITY",
1553 "DACL_COMPUTED",
1554 "SACL_COMPUTED",
1555 "DACL_AUTO_INHERITED",
1556 "SACL_AUTO_INHERITED",
1557 "DACL_PROTECTED",
1558 "SACL_PROTECTED",
1559 "RM_CONTROL_VALID",
1560 "SELF_RELATIVE",
1561 ],
1562 ),
1563 LEIntField("OwnerSidOffset", None),
1564 LEIntField("GroupSidOffset", None),
1565 LEIntField("SACLOffset", None),
1566 LEIntField("DACLOffset", None),
1567 _NTLMPayloadField(
1568 "Data",
1569 OFFSET,
1570 [
1571 ConditionalField(
1572 PacketField("OwnerSid", WINNT_SID(), WINNT_SID),
1573 lambda pkt: pkt.OwnerSidOffset != 0,
1574 ),
1575 ConditionalField(
1576 PacketField("GroupSid", WINNT_SID(), WINNT_SID),
1577 lambda pkt: pkt.GroupSidOffset != 0,
1578 ),
1579 ConditionalField(
1580 PacketField("SACL", WINNT_ACL(), WINNT_ACL),
1581 lambda pkt: pkt.Control.SACL_PRESENT,
1582 ),
1583 ConditionalField(
1584 PacketField("DACL", WINNT_ACL(), WINNT_ACL),
1585 lambda pkt: pkt.Control.DACL_PRESENT,
1586 ),
1587 ],
1588 offset_name="Offset",
1589 ),
1590 ]
1591
1592 def post_build(self, pkt, pay):
1593 # type: (bytes, bytes) -> bytes
1594 return (
1595 _NTLM_post_build(
1596 self,
1597 pkt,
1598 self.OFFSET,
1599 {
1600 "OwnerSid": 4,
1601 "GroupSid": 8,
1602 "SACL": 12,
1603 "DACL": 16,
1604 },
1605 config=[
1606 ("Offset", _NTLM_ENUM.OFFSET),
1607 ],
1608 )
1609 + pay
1610 )
1611
1612
1613# [MS-FSCC] 2.4.2 FileAllInformation
1614
1615
1616class FileAllInformation(Packet):
1617 fields_desc = [
1618 PacketField("BasicInformation", FileBasicInformation(), FileBasicInformation),
1619 PacketField(
1620 "StandardInformation", FileStandardInformation(), FileStandardInformation
1621 ),
1622 PacketField(
1623 "InternalInformation", FileInternalInformation(), FileInternalInformation
1624 ),
1625 PacketField("EaInformation", FileEaInformation(), FileEaInformation),
1626 PacketField(
1627 "AccessInformation", FileAccessInformation(), FileAccessInformation
1628 ),
1629 PacketField(
1630 "PositionInformation", FilePositionInformation(), FilePositionInformation
1631 ),
1632 PacketField("ModeInformation", FileModeInformation(), FileModeInformation),
1633 PacketField(
1634 "AlignmentInformation", FileAlignmentInformation(), FileAlignmentInformation
1635 ),
1636 PacketField("NameInformation", FILE_NAME_INFORMATION(), FILE_NAME_INFORMATION),
1637 ]
1638
1639
1640# [MS-FSCC] 2.5.1 FileFsAttributeInformation
1641
1642
1643class FileFsAttributeInformation(Packet):
1644 fields_desc = [
1645 FlagsField(
1646 "FileSystemAttributes",
1647 0x00C706FF,
1648 -32,
1649 {
1650 0x02000000: "FILE_SUPPORTS_USN_JOURNAL",
1651 0x01000000: "FILE_SUPPORTS_OPEN_BY_FILE_ID",
1652 0x00800000: "FILE_SUPPORTS_EXTENDED_ATTRIBUTES",
1653 0x00400000: "FILE_SUPPORTS_HARD_LINKS",
1654 0x00200000: "FILE_SUPPORTS_TRANSACTIONS",
1655 0x00100000: "FILE_SEQUENTIAL_WRITE_ONCE",
1656 0x00080000: "FILE_READ_ONLY_VOLUME",
1657 0x00040000: "FILE_NAMED_STREAMS",
1658 0x00020000: "FILE_SUPPORTS_ENCRYPTION",
1659 0x00010000: "FILE_SUPPORTS_OBJECT_IDS",
1660 0x00008000: "FILE_VOLUME_IS_COMPRESSED",
1661 0x00000100: "FILE_SUPPORTS_REMOTE_STORAGE",
1662 0x00000080: "FILE_SUPPORTS_REPARSE_POINTS",
1663 0x00000040: "FILE_SUPPORTS_SPARSE_FILES",
1664 0x00000020: "FILE_VOLUME_QUOTAS",
1665 0x00000010: "FILE_FILE_COMPRESSION",
1666 0x00000008: "FILE_PERSISTENT_ACLS",
1667 0x00000004: "FILE_UNICODE_ON_DISK",
1668 0x00000002: "FILE_CASE_PRESERVED_NAMES",
1669 0x00000001: "FILE_CASE_SENSITIVE_SEARCH",
1670 0x04000000: "FILE_SUPPORT_INTEGRITY_STREAMS",
1671 0x08000000: "FILE_SUPPORTS_BLOCK_REFCOUNTING",
1672 0x10000000: "FILE_SUPPORTS_SPARSE_VDL",
1673 },
1674 ),
1675 LEIntField("MaximumComponentNameLength", 255),
1676 FieldLenField(
1677 "FileSystemNameLength", None, length_of="FileSystemName", fmt="<I"
1678 ),
1679 StrLenFieldUtf16(
1680 "FileSystemName", b"NTFS", length_from=lambda pkt: pkt.FileSystemNameLength
1681 ),
1682 ]
1683
1684
1685# [MS-FSCC] 2.5.8 FileFsSizeInformation
1686
1687
1688class FileFsSizeInformation(Packet):
1689 fields_desc = [
1690 LELongField("TotalAllocationUnits", 10485760),
1691 LELongField("AvailableAllocationUnits", 1048576),
1692 LEIntField("SectorsPerAllocationUnit", 8),
1693 LEIntField("BytesPerSector", 512),
1694 ]
1695
1696
1697# [MS-FSCC] 2.5.9 FileFsVolumeInformation
1698
1699
1700class FileFsVolumeInformation(Packet):
1701 fields_desc = [
1702 UTCTimeField(
1703 "VolumeCreationTime",
1704 None,
1705 fmt="<Q",
1706 epoch=[1601, 1, 1, 0, 0, 0],
1707 custom_scaling=1e7,
1708 ),
1709 LEIntField("VolumeSerialNumber", 0),
1710 LEIntField("VolumeLabelLength", 0),
1711 ByteField("SupportsObjects", 1),
1712 ByteField("Reserved", 0),
1713 StrNullFieldUtf16("VolumeLabel", b"C"),
1714 ]
1715
1716
1717# [MS-FSCC] 2.7.1 FILE_NOTIFY_INFORMATION
1718
1719
1720class FILE_NOTIFY_INFORMATION(Packet):
1721 fields_desc = [
1722 IntField("NextEntryOffset", 0),
1723 LEIntEnumField(
1724 "Action",
1725 0,
1726 {
1727 0x00000001: "FILE_ACTION_ADDED",
1728 0x00000002: "FILE_ACTION_REMOVED",
1729 0x00000003: "FILE_ACTION_MODIFIED",
1730 0x00000004: "FILE_ACTION_RENAMED_OLD_NAME",
1731 0x00000005: "FILE_ACTION_RENAMED_NEW_NAME",
1732 0x00000006: "FILE_ACTION_ADDED_STREAM",
1733 0x00000007: "FILE_ACTION_REMOVED_STREAM",
1734 0x00000008: "FILE_ACTION_MODIFIED_STREAM",
1735 0x00000009: "FILE_ACTION_REMOVED_BY_DELETE",
1736 0x0000000A: "FILE_ACTION_ID_NOT_TUNNELLED",
1737 0x0000000B: "FILE_ACTION_TUNNELLED_ID_COLLISION",
1738 },
1739 ),
1740 FieldLenField(
1741 "FileNameLength",
1742 None,
1743 length_of="FileName",
1744 fmt="<I",
1745 ),
1746 StrLenFieldUtf16("FileName", b"", length_from=lambda x: x.FileNameLength),
1747 StrLenField(
1748 "pad",
1749 b"",
1750 length_from=lambda x: (
1751 (x.NextEntryOffset - x.FileNameLength) if x.NextEntryOffset else 0
1752 ),
1753 ),
1754 ]
1755
1756 def default_payload_class(self, s):
1757 return conf.padding_layer
1758
1759
1760_SMB2_CONFIG = [
1761 ("BufferOffset", _NTLM_ENUM.OFFSET),
1762 ("Len", _NTLM_ENUM.LEN),
1763]
1764
1765
1766def _SMB2_post_build(self, p, pay_offset, fields):
1767 """Util function to build the offset and populate the lengths"""
1768 return _NTLM_post_build(self, p, pay_offset, fields, config=_SMB2_CONFIG)
1769
1770
1771# SMB2 sect 2.1
1772
1773
1774class DirectTCP(NBTSession):
1775 name = "Direct TCP"
1776 MAXLENGTH = 0xFFFFFF
1777 fields_desc = [ByteField("zero", 0), ThreeBytesField("LENGTH", None)]
1778
1779
1780# SMB2 sect 2.2.1.1
1781
1782
1783class SMB2_Header(Packet):
1784 __slots__ = ["_decrypted"]
1785
1786 name = "SMB2 Header"
1787 fields_desc = [
1788 StrFixedLenField("Start", b"\xfeSMB", 4),
1789 LEShortField("StructureSize", 64),
1790 LEShortField("CreditCharge", 0),
1791 LEIntEnumField("Status", 0, STATUS_ERREF),
1792 LEShortEnumField("Command", 0, SMB2_COM),
1793 LEShortField("CreditRequest", 0),
1794 FlagsField(
1795 "Flags",
1796 0,
1797 -32,
1798 {
1799 0x00000001: "SMB2_FLAGS_SERVER_TO_REDIR",
1800 0x00000002: "SMB2_FLAGS_ASYNC_COMMAND",
1801 0x00000004: "SMB2_FLAGS_RELATED_OPERATIONS",
1802 0x00000008: "SMB2_FLAGS_SIGNED",
1803 0x10000000: "SMB2_FLAGS_DFS_OPERATIONS",
1804 0x20000000: "SMB2_FLAGS_REPLAY_OPERATION",
1805 },
1806 ),
1807 XLEIntField("NextCommand", 0),
1808 LELongField("MID", 0), # MessageID
1809 # ASYNC
1810 ConditionalField(
1811 LELongField("AsyncId", 0), lambda pkt: pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND
1812 ),
1813 # SYNC
1814 ConditionalField(
1815 LEIntField("PID", 0), # Reserved, but PID per wireshark
1816 lambda pkt: not pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND,
1817 ),
1818 ConditionalField(
1819 LEIntField("TID", 0), # TreeID
1820 lambda pkt: not pkt.Flags.SMB2_FLAGS_ASYNC_COMMAND,
1821 ),
1822 # COMMON
1823 LELongField("SessionId", 0),
1824 XStrFixedLenField("SecuritySignature", 0, length=16),
1825 ]
1826
1827 _SMB2_OK_RETURNCODES = (
1828 # sect 3.3.4.4
1829 (0xC0000016, 0x0001), # STATUS_MORE_PROCESSING_REQUIRED
1830 (0x80000005, 0x0008), # STATUS_BUFFER_OVERFLOW (Read)
1831 (0x80000005, 0x0010), # STATUS_BUFFER_OVERFLOW (QueryInfo)
1832 (0x80000005, 0x000B), # STATUS_BUFFER_OVERFLOW (IOCTL)
1833 (0xC000000D, 0x000B), # STATUS_INVALID_PARAMETER
1834 (0x0000010C, 0x000F), # STATUS_NOTIFY_ENUM_DIR
1835 )
1836
1837 def __init__(self, *args, **kwargs):
1838 # The parent passes whether this packet was decrypted or not.
1839 self._decrypted = kwargs.pop("_decrypted", False)
1840 super(SMB2_Header, self).__init__(*args, **kwargs)
1841
1842 def guess_payload_class(self, payload):
1843 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR and self.Status != 0x00000000:
1844 # Check status for responses
1845 if (self.Status, self.Command) not in SMB2_Header._SMB2_OK_RETURNCODES:
1846 return SMB2_Error_Response
1847 if self.Command == 0x0000: # Negotiate
1848 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1849 return SMB2_Negotiate_Protocol_Response
1850 return SMB2_Negotiate_Protocol_Request
1851 elif self.Command == 0x0001: # Setup
1852 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1853 return SMB2_Session_Setup_Response
1854 return SMB2_Session_Setup_Request
1855 elif self.Command == 0x0002: # Logoff
1856 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1857 return SMB2_Session_Logoff_Response
1858 return SMB2_Session_Logoff_Request
1859 elif self.Command == 0x0003: # TREE connect
1860 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1861 return SMB2_Tree_Connect_Response
1862 return SMB2_Tree_Connect_Request
1863 elif self.Command == 0x0004: # TREE disconnect
1864 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1865 return SMB2_Tree_Disconnect_Response
1866 return SMB2_Tree_Disconnect_Request
1867 elif self.Command == 0x0005: # Create
1868 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1869 return SMB2_Create_Response
1870 return SMB2_Create_Request
1871 elif self.Command == 0x0006: # Close
1872 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1873 return SMB2_Close_Response
1874 return SMB2_Close_Request
1875 elif self.Command == 0x0008: # Read
1876 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1877 return SMB2_Read_Response
1878 return SMB2_Read_Request
1879 elif self.Command == 0x0009: # Write
1880 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1881 return SMB2_Write_Response
1882 return SMB2_Write_Request
1883 elif self.Command == 0x000C: # Cancel
1884 return SMB2_Cancel_Request
1885 elif self.Command == 0x000D: # Echo
1886 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1887 return SMB2_Echo_Response
1888 return SMB2_Echo_Request
1889 elif self.Command == 0x000E: # Query directory
1890 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1891 return SMB2_Query_Directory_Response
1892 return SMB2_Query_Directory_Request
1893 elif self.Command == 0x000F: # Change Notify
1894 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1895 return SMB2_Change_Notify_Response
1896 return SMB2_Change_Notify_Request
1897 elif self.Command == 0x0010: # Query info
1898 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1899 return SMB2_Query_Info_Response
1900 return SMB2_Query_Info_Request
1901 elif self.Command == 0x0011: # Set info
1902 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1903 return SMB2_Set_Info_Response
1904 return SMB2_Set_Info_Request
1905 elif self.Command == 0x000B: # IOCTL
1906 if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
1907 return SMB2_IOCTL_Response
1908 return SMB2_IOCTL_Request
1909 return super(SMB2_Header, self).guess_payload_class(payload)
1910
1911 def _calc_signature(
1912 self, s, dialect, SigningSessionKey, SigningAlgorithmId=None, IsClient=None
1913 ):
1914 """
1915 This function calculates the signature of a SMB2 packet.
1916 Detail is from [MS-SMB2] 3.1.4.1
1917 """
1918 if len(s) <= 64:
1919 log_runtime.warning("Cannot sign invalid SMB packet !")
1920 return s
1921 if dialect in [0x0300, 0x0302, 0x0311]: # SMB 3
1922 if dialect == 0x0311: # SMB 3.1.1
1923 if IsClient is None:
1924 raise Exception("SMB 3.1.1 needs a IsClient")
1925 if SigningAlgorithmId is None:
1926 SigningAlgorithmId = "AES-CMAC" # AES-128-CMAC
1927 else:
1928 SigningAlgorithmId = "AES-CMAC" # AES-128-CMAC
1929 if "GMAC" in SigningAlgorithmId:
1930 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
1931
1932 aesgcm = AESGCM(SigningSessionKey)
1933 nonce = struct.pack("<Q", self.MID) + struct.pack(
1934 "<I",
1935 (0 if IsClient else 1) | (0x8000000 if self.Command == 9 else 0),
1936 )
1937 sig = aesgcm.encrypt(nonce, b"", s)
1938 elif "CMAC" in SigningAlgorithmId:
1939 from cryptography.hazmat.primitives import cmac
1940 from cryptography.hazmat.primitives.ciphers import algorithms
1941
1942 c = cmac.CMAC(algorithms.AES(SigningSessionKey))
1943 c.update(s)
1944 sig = c.finalize()
1945 elif "HMAC" in SigningAlgorithmId:
1946 from scapy.layers.tls.crypto.h_mac import Hmac_SHA256
1947
1948 sig = Hmac_SHA256(SigningSessionKey).digest(s)
1949 sig = sig[:16]
1950 else:
1951 raise ValueError("Unknown SigningAlgorithmId")
1952 elif dialect in [0x0210, 0x0202]: # SMB 2.1 or SMB 2.0.2
1953 from scapy.layers.tls.crypto.h_mac import Hmac_SHA256
1954
1955 sig = Hmac_SHA256(SigningSessionKey).digest(s)
1956 sig = sig[:16]
1957 else:
1958 log_runtime.warning("Unknown SMB Version %s ! Cannot sign." % dialect)
1959 sig = b"\x00" * 16
1960 return sig
1961
1962 def sign(self, dialect, SigningSessionKey, SigningAlgorithmId=None, IsClient=None):
1963 """
1964 [MS-SMB2] 3.1.4.1 - Signing An Outgoing Message
1965 """
1966 # Set the current signature to nul
1967 self.SecuritySignature = b"\x00" * 16
1968 # Calculate the signature
1969 s = bytes(self)
1970 self.SecuritySignature = self._calc_signature(
1971 s,
1972 dialect=dialect,
1973 SigningSessionKey=SigningSessionKey,
1974 SigningAlgorithmId=SigningAlgorithmId,
1975 IsClient=IsClient,
1976 )
1977 # we make sure the payload is static
1978 self.payload = conf.raw_layer(load=s[64:])
1979
1980 def verify(
1981 self, dialect, SigningSessionKey, SigningAlgorithmId=None, IsClient=None
1982 ):
1983 """
1984 [MS-SMB2] sect 3.2.5.1.3 - Verifying the signature
1985 """
1986 s = bytes(self)
1987 # Set SecuritySignature to nul
1988 s = s[:48] + b"\x00" * 16 + s[64:]
1989 # Calculate the signature
1990 sig = self._calc_signature(
1991 s,
1992 dialect=dialect,
1993 SigningSessionKey=SigningSessionKey,
1994 SigningAlgorithmId=SigningAlgorithmId,
1995 IsClient=IsClient,
1996 )
1997 if self.SecuritySignature != sig:
1998 log_runtime.error("SMB signature is invalid !")
1999 raise Exception("ERROR: SMB signature is invalid !")
2000
2001 def encrypt(self, dialect, EncryptionKey, CipherId):
2002 """
2003 [MS-SMB2] sect 3.1.4.3 - Encrypting the Message
2004 """
2005 if dialect < 0x0300:
2006 raise Exception("Encryption is not supported on this SMB dialect !")
2007 elif dialect < 0x0311 and CipherId != "AES-128-CCM":
2008 raise Exception("CipherId is not supported on this SMB dialect !")
2009
2010 data = bytes(self)
2011 smbt = SMB2_Transform_Header(
2012 OriginalMessageSize=len(self),
2013 SessionId=self.SessionId,
2014 Flags=0x0001,
2015 )
2016 if "GCM" in CipherId:
2017 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
2018
2019 nonce = os.urandom(12)
2020 cipher = AESGCM(EncryptionKey)
2021 elif "CCM" in CipherId:
2022 from cryptography.hazmat.primitives.ciphers.aead import AESCCM
2023
2024 nonce = os.urandom(11)
2025 cipher = AESCCM(EncryptionKey)
2026 else:
2027 raise Exception("Unknown CipherId !")
2028
2029 # Add nonce to header and build the auth data
2030 smbt.Nonce = nonce
2031 aad = bytes(smbt)[20:]
2032
2033 # Perform the actual encryption
2034 data = cipher.encrypt(nonce, data, aad)
2035
2036 # Put the auth tag in the Signature field
2037 smbt.Signature, data = data[-16:], data[:-16]
2038
2039 return smbt / data
2040
2041
2042class _SMB2_Payload(Packet):
2043 def do_dissect_payload(self, s):
2044 # There can be padding between this layer and the next one
2045 if self.underlayer and isinstance(self.underlayer, SMB2_Header):
2046 if self.underlayer.NextCommand:
2047 padlen = self.underlayer.NextCommand - (64 + len(self.raw_packet_cache))
2048 if padlen:
2049 self.add_payload(s[:padlen])
2050 s = s[padlen:]
2051 super(_SMB2_Payload, self).do_dissect_payload(s)
2052
2053 def answers(self, other):
2054 return (
2055 isinstance(other, _SMB2_Payload)
2056 and self.__class__ != other.__class__
2057 and (self.Command == other.Command or self.Command == -1)
2058 )
2059
2060 def guess_payload_class(self, s):
2061 if self.underlayer and isinstance(self.underlayer, SMB2_Header):
2062 if self.underlayer.NextCommand:
2063 return SMB2_Header
2064 return super(_SMB2_Payload, self).guess_payload_class(s)
2065
2066
2067# sect 2.2.2
2068
2069
2070class SMB2_Error_Response(_SMB2_Payload):
2071 Command = -1
2072 __slots__ = ["NTStatus"] # extra info
2073 name = "SMB2 Error Response"
2074 fields_desc = [
2075 XLEShortField("StructureSize", 0x09),
2076 ByteField("ErrorContextCount", 0),
2077 ByteField("Reserved", 0),
2078 FieldLenField("ByteCount", None, fmt="<I", length_of="ErrorData"),
2079 XStrLenField("ErrorData", b"", length_from=lambda pkt: pkt.ByteCount),
2080 ]
2081
2082
2083bind_top_down(SMB2_Header, SMB2_Error_Response, Flags=1) # SMB2_FLAGS_SERVER_TO_REDIR
2084
2085# sect 2.2.2.2.2
2086
2087
2088class MOVE_DST_IPADDR(Packet):
2089 fields_desc = [
2090 # Wireshark appears to get this wrong
2091 LEIntEnumField("Type", 1, {1: "IPv4", 2: "IPv6"}),
2092 IntField("Reserved", 0),
2093 MultipleTypeField(
2094 [(IP6Field("IPAddress", None), lambda pkt: pkt.Type == 2)],
2095 IPField("IPAddress", None),
2096 ),
2097 ConditionalField(
2098 # For IPv4
2099 StrFixedLenField("Reserved2", b"", length=12),
2100 lambda pkt: pkt.Type == 1,
2101 ),
2102 ]
2103
2104 def default_payload_class(self, payload):
2105 return conf.padding_layer
2106
2107
2108class SMB2_Error_Share_Redirect_Context_Response(_NTLMPayloadPacket):
2109 name = "Share Redirect Error Context Response"
2110 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2111 fields_desc = [
2112 XLEIntField("StructureSize", 0x30),
2113 LEIntEnumField("NotificationType", 3, {3: "SHARE_MOVE_NOTIFICATION"}),
2114 XLEIntField("ResourceNameBufferOffset", None),
2115 LEIntField("ResourceNameLen", None),
2116 ShortField("Reserved", 0),
2117 ShortEnumField("TargetType", 0, {0: "IP"}),
2118 FieldLenField("IPAddrCount", None, fmt="<I", count_of="IPAddrMoveList"),
2119 PacketListField(
2120 "IPAddrMoveList",
2121 [],
2122 MOVE_DST_IPADDR,
2123 count_from=lambda pkt: pkt.IPAddrCount,
2124 ),
2125 _NTLMPayloadField(
2126 "Buffer",
2127 lambda pkt: 24 + len(pkt.IPAddrMoveList) * 24,
2128 [
2129 StrLenFieldUtf16(
2130 "ResourceName", b"", length_from=lambda pkt: pkt.ResourceNameLen
2131 ),
2132 ],
2133 ),
2134 ]
2135
2136 def post_build(self, pkt, pay):
2137 # type: (bytes, bytes) -> bytes
2138 return (
2139 _SMB2_post_build(
2140 self,
2141 pkt,
2142 24 + len(self.IPAddrMoveList) * 24,
2143 {
2144 "ResourceName": 8,
2145 },
2146 )
2147 + pay
2148 )
2149
2150
2151# sect 2.2.2.1
2152
2153
2154class SMB2_Error_ContextResponse(Packet):
2155 fields_desc = [
2156 FieldLenField("ErrorDatalength", None, fmt="<I", length_of="ErrorContextData"),
2157 LEIntEnumField("ErrorId", 0, {0: "DEFAULT", 0x72645253: "SHARE_REDIRECT"}),
2158 MultipleTypeField(
2159 [
2160 (
2161 PacketField(
2162 "ErrorContextData",
2163 SMB2_Error_Share_Redirect_Context_Response(),
2164 SMB2_Error_Share_Redirect_Context_Response,
2165 ),
2166 lambda pkt: pkt.ErrorId == 0x72645253,
2167 )
2168 ],
2169 XStrLenField(
2170 "ErrorContextData", b"", length_from=lambda pkt: pkt.ErrorDatalength
2171 ),
2172 ),
2173 ]
2174
2175
2176# sect 2.2.3
2177
2178
2179class SMB2_Negotiate_Context(Packet):
2180 name = "SMB2 Negotiate Context"
2181 fields_desc = [
2182 LEShortEnumField("ContextType", 0x0, SMB2_NEGOTIATE_CONTEXT_TYPES),
2183 LenField("DataLength", None, fmt="<H"),
2184 IntField("Reserved", 0),
2185 ]
2186
2187 def default_payload_class(self, payload):
2188 return conf.padding_layer
2189
2190
2191class SMB2_Negotiate_Protocol_Request(_SMB2_Payload, _NTLMPayloadPacket):
2192 name = "SMB2 Negotiate Protocol Request"
2193 Command = 0x0000
2194 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2195 fields_desc = [
2196 XLEShortField("StructureSize", 0x24),
2197 FieldLenField("DialectCount", None, fmt="<H", count_of="Dialects"),
2198 # SecurityMode
2199 FlagsField("SecurityMode", 0, -16, SMB2_SECURITY_MODE),
2200 LEShortField("Reserved", 0),
2201 # Capabilities
2202 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
2203 UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2204 XLEIntField("NegotiateContextsBufferOffset", None),
2205 LEShortField("NegotiateContextsCount", None),
2206 ShortField("Reserved2", 0),
2207 FieldListField(
2208 "Dialects",
2209 [0x0202],
2210 LEShortEnumField("", 0x0, SMB_DIALECTS),
2211 count_from=lambda pkt: pkt.DialectCount,
2212 ),
2213 _NTLMPayloadField(
2214 "Buffer",
2215 lambda pkt: 64 + 36 + len(pkt.Dialects) * 2,
2216 [
2217 # Field only exists if Dialects contains 0x0311
2218 FieldListField(
2219 "NegotiateContexts",
2220 [],
2221 ReversePadField(
2222 PacketField("Context", None, SMB2_Negotiate_Context),
2223 8,
2224 ),
2225 count_from=lambda pkt: pkt.NegotiateContextsCount,
2226 ),
2227 ],
2228 ),
2229 ]
2230
2231 def post_build(self, pkt, pay):
2232 # type: (bytes, bytes) -> bytes
2233 return (
2234 _NTLM_post_build(
2235 self,
2236 pkt,
2237 64 + 36 + len(self.Dialects) * 2,
2238 {
2239 "NegotiateContexts": 28,
2240 },
2241 config=[
2242 ("BufferOffset", _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8),
2243 ("Count", _NTLM_ENUM.COUNT),
2244 ],
2245 )
2246 + pay
2247 )
2248
2249
2250bind_top_down(
2251 SMB2_Header,
2252 SMB2_Negotiate_Protocol_Request,
2253 Command=0x0000,
2254)
2255
2256# sect 2.2.3.1.1
2257
2258
2259class SMB2_Preauth_Integrity_Capabilities(Packet):
2260 name = "SMB2 Preauth Integrity Capabilities"
2261 fields_desc = [
2262 # According to the spec, this field value must be greater than 0
2263 # (cf Section 2.2.3.1.1 of MS-SMB2.pdf)
2264 FieldLenField("HashAlgorithmCount", None, fmt="<H", count_of="HashAlgorithms"),
2265 FieldLenField("SaltLength", None, fmt="<H", length_of="Salt"),
2266 FieldListField(
2267 "HashAlgorithms",
2268 [0x0001],
2269 LEShortEnumField(
2270 "",
2271 0x0,
2272 SMB2_HASH_ALGORITHMS,
2273 ),
2274 count_from=lambda pkt: pkt.HashAlgorithmCount,
2275 ),
2276 XStrLenField("Salt", "", length_from=lambda pkt: pkt.SaltLength),
2277 ]
2278
2279 def default_payload_class(self, payload):
2280 return conf.padding_layer
2281
2282
2283bind_layers(
2284 SMB2_Negotiate_Context, SMB2_Preauth_Integrity_Capabilities, ContextType=0x0001
2285)
2286
2287# sect 2.2.3.1.2
2288
2289
2290class SMB2_Encryption_Capabilities(Packet):
2291 name = "SMB2 Encryption Capabilities"
2292 fields_desc = [
2293 # According to the spec, this field value must be greater than 0
2294 # (cf Section 2.2.3.1.2 of MS-SMB2.pdf)
2295 FieldLenField("CipherCount", None, fmt="<H", count_of="Ciphers"),
2296 FieldListField(
2297 "Ciphers",
2298 [0x0001],
2299 LEShortEnumField(
2300 "",
2301 0x0,
2302 SMB2_ENCRYPTION_CIPHERS,
2303 ),
2304 count_from=lambda pkt: pkt.CipherCount,
2305 ),
2306 ]
2307
2308 def default_payload_class(self, payload):
2309 return conf.padding_layer
2310
2311
2312bind_layers(SMB2_Negotiate_Context, SMB2_Encryption_Capabilities, ContextType=0x0002)
2313
2314# sect 2.2.3.1.3
2315
2316
2317class SMB2_Compression_Capabilities(Packet):
2318 name = "SMB2 Compression Capabilities"
2319 fields_desc = [
2320 FieldLenField(
2321 "CompressionAlgorithmCount",
2322 None,
2323 fmt="<H",
2324 count_of="CompressionAlgorithms",
2325 ),
2326 ShortField("Padding", 0x0),
2327 LEIntEnumField(
2328 "Flags",
2329 0x0,
2330 {
2331 0x00000000: "SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE",
2332 0x00000001: "SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED",
2333 },
2334 ),
2335 FieldListField(
2336 "CompressionAlgorithms",
2337 None,
2338 LEShortEnumField("", 0x0, SMB2_COMPRESSION_ALGORITHMS),
2339 count_from=lambda pkt: pkt.CompressionAlgorithmCount,
2340 ),
2341 ]
2342
2343 def default_payload_class(self, payload):
2344 return conf.padding_layer
2345
2346
2347bind_layers(SMB2_Negotiate_Context, SMB2_Compression_Capabilities, ContextType=0x0003)
2348
2349# sect 2.2.3.1.4
2350
2351
2352class SMB2_Netname_Negotiate_Context_ID(Packet):
2353 name = "SMB2 Netname Negotiate Context ID"
2354 fields_desc = [
2355 StrLenFieldUtf16(
2356 "NetName", "", length_from=lambda pkt: pkt.underlayer.DataLength
2357 )
2358 ]
2359
2360 def default_payload_class(self, payload):
2361 return conf.padding_layer
2362
2363
2364bind_layers(
2365 SMB2_Negotiate_Context, SMB2_Netname_Negotiate_Context_ID, ContextType=0x0005
2366)
2367
2368# sect 2.2.3.1.5
2369
2370
2371class SMB2_Transport_Capabilities(Packet):
2372 name = "SMB2 Transport Capabilities"
2373 fields_desc = [
2374 FlagsField(
2375 "Flags",
2376 0x0,
2377 -32,
2378 {
2379 0x00000001: "SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY",
2380 },
2381 ),
2382 ]
2383
2384 def default_payload_class(self, payload):
2385 return conf.padding_layer
2386
2387
2388bind_layers(SMB2_Negotiate_Context, SMB2_Transport_Capabilities, ContextType=0x0006)
2389
2390# sect 2.2.3.1.6
2391
2392
2393class SMB2_RDMA_Transform_Capabilities(Packet):
2394 name = "SMB2 RDMA Transform Capabilities"
2395 fields_desc = [
2396 FieldLenField("TransformCount", None, fmt="<H", count_of="RDMATransformIds"),
2397 LEShortField("Reserved1", 0),
2398 LEIntField("Reserved2", 0),
2399 FieldListField(
2400 "RDMATransformIds",
2401 None,
2402 LEShortEnumField(
2403 "",
2404 0x0,
2405 {
2406 0x0000: "SMB2_RDMA_TRANSFORM_NONE",
2407 0x0001: "SMB2_RDMA_TRANSFORM_ENCRYPTION",
2408 0x0002: "SMB2_RDMA_TRANSFORM_SIGNING",
2409 },
2410 ),
2411 count_from=lambda pkt: pkt.TransformCount,
2412 ),
2413 ]
2414
2415 def default_payload_class(self, payload):
2416 return conf.padding_layer
2417
2418
2419bind_layers(
2420 SMB2_Negotiate_Context, SMB2_RDMA_Transform_Capabilities, ContextType=0x0007
2421)
2422
2423# sect 2.2.3.1.7
2424
2425
2426class SMB2_Signing_Capabilities(Packet):
2427 name = "SMB2 Signing Capabilities"
2428 fields_desc = [
2429 FieldLenField(
2430 "SigningAlgorithmCount", None, fmt="<H", count_of="SigningAlgorithms"
2431 ),
2432 FieldListField(
2433 "SigningAlgorithms",
2434 None,
2435 LEShortEnumField(
2436 "",
2437 0x0,
2438 SMB2_SIGNING_ALGORITHMS,
2439 ),
2440 count_from=lambda pkt: pkt.SigningAlgorithmCount,
2441 ),
2442 ]
2443
2444 def default_payload_class(self, payload):
2445 return conf.padding_layer
2446
2447
2448bind_layers(SMB2_Negotiate_Context, SMB2_Signing_Capabilities, ContextType=0x0008)
2449
2450# sect 2.2.4
2451
2452
2453class SMB2_Negotiate_Protocol_Response(_SMB2_Payload, _NTLMPayloadPacket):
2454 name = "SMB2 Negotiate Protocol Response"
2455 Command = 0x0000
2456 OFFSET = 64 + 64
2457 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2458 fields_desc = [
2459 XLEShortField("StructureSize", 0x41),
2460 FlagsField("SecurityMode", 0, -16, SMB2_SECURITY_MODE),
2461 LEShortEnumField("DialectRevision", 0x0, SMB_DIALECTS),
2462 LEShortField("NegotiateContextsCount", None),
2463 UUIDField("GUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2464 # Capabilities
2465 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
2466 LEIntField("MaxTransactionSize", 65536),
2467 LEIntField("MaxReadSize", 65536),
2468 LEIntField("MaxWriteSize", 65536),
2469 UTCTimeField(
2470 "ServerTime",
2471 None,
2472 fmt="<Q",
2473 epoch=[1601, 1, 1, 0, 0, 0],
2474 custom_scaling=1e7,
2475 ),
2476 UTCTimeField(
2477 "ServerStartTime",
2478 None,
2479 fmt="<Q",
2480 epoch=[1601, 1, 1, 0, 0, 0],
2481 custom_scaling=1e7,
2482 ),
2483 XLEShortField("SecurityBlobBufferOffset", None),
2484 LEShortField("SecurityBlobLen", None),
2485 XLEIntField("NegotiateContextsBufferOffset", None),
2486 _NTLMPayloadField(
2487 "Buffer",
2488 OFFSET,
2489 [
2490 PacketLenField(
2491 "SecurityBlob",
2492 None,
2493 GSSAPI_BLOB,
2494 length_from=lambda x: x.SecurityBlobLen,
2495 ),
2496 # Field only exists if Dialect is 0x0311
2497 FieldListField(
2498 "NegotiateContexts",
2499 [],
2500 ReversePadField(
2501 PacketField("Context", None, SMB2_Negotiate_Context),
2502 8,
2503 ),
2504 count_from=lambda pkt: pkt.NegotiateContextsCount,
2505 ),
2506 ],
2507 force_order=["SecurityBlob", "NegotiateContexts"],
2508 ),
2509 ]
2510
2511 def post_build(self, pkt, pay):
2512 # type: (bytes, bytes) -> bytes
2513 pkt = _NTLM_post_build(
2514 self,
2515 pkt,
2516 self.OFFSET,
2517 {
2518 "SecurityBlob": 56,
2519 "NegotiateContexts": 60,
2520 },
2521 config=[
2522 (
2523 "BufferOffset",
2524 {
2525 "SecurityBlob": _NTLM_ENUM.OFFSET,
2526 "NegotiateContexts": _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8,
2527 },
2528 ),
2529 ],
2530 )
2531 if getattr(self, "SecurityBlob", None):
2532 if self.SecurityBlobLen is None:
2533 pkt = pkt[:58] + struct.pack("<H", len(self.SecurityBlob)) + pkt[60:]
2534 if getattr(self, "NegotiateContexts", None):
2535 if self.NegotiateContextsCount is None:
2536 pkt = pkt[:6] + struct.pack("<H", len(self.NegotiateContexts)) + pkt[8:]
2537 return pkt + pay
2538
2539
2540bind_top_down(
2541 SMB2_Header,
2542 SMB2_Negotiate_Protocol_Response,
2543 Command=0x0000,
2544 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2545)
2546
2547# sect 2.2.5
2548
2549
2550class SMB2_Session_Setup_Request(_SMB2_Payload, _NTLMPayloadPacket):
2551 name = "SMB2 Session Setup Request"
2552 Command = 0x0001
2553 OFFSET = 24 + 64
2554 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2555 fields_desc = [
2556 XLEShortField("StructureSize", 0x19),
2557 FlagsField("Flags", 0, -8, ["SMB2_SESSION_FLAG_BINDING"]),
2558 FlagsField("SecurityMode", 0, -8, SMB2_SECURITY_MODE),
2559 FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES),
2560 LEIntField("Channel", 0),
2561 XLEShortField("SecurityBlobBufferOffset", None),
2562 LEShortField("SecurityBlobLen", None),
2563 XLELongField("PreviousSessionId", 0),
2564 _NTLMPayloadField(
2565 "Buffer",
2566 OFFSET,
2567 [
2568 PacketField("SecurityBlob", None, GSSAPI_BLOB),
2569 ],
2570 ),
2571 ]
2572
2573 def post_build(self, pkt, pay):
2574 # type: (bytes, bytes) -> bytes
2575 return (
2576 _SMB2_post_build(
2577 self,
2578 pkt,
2579 self.OFFSET,
2580 {
2581 "SecurityBlob": 12,
2582 },
2583 )
2584 + pay
2585 )
2586
2587
2588bind_top_down(
2589 SMB2_Header,
2590 SMB2_Session_Setup_Request,
2591 Command=0x0001,
2592)
2593
2594# sect 2.2.6
2595
2596
2597class SMB2_Session_Setup_Response(_SMB2_Payload, _NTLMPayloadPacket):
2598 name = "SMB2 Session Setup Response"
2599 Command = 0x0001
2600 OFFSET = 8 + 64
2601 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2602 fields_desc = [
2603 XLEShortField("StructureSize", 0x9),
2604 FlagsField(
2605 "SessionFlags",
2606 0,
2607 -16,
2608 {
2609 0x0001: "IS_GUEST",
2610 0x0002: "IS_NULL",
2611 0x0004: "ENCRYPT_DATA",
2612 },
2613 ),
2614 XLEShortField("SecurityBufferOffset", None),
2615 LEShortField("SecurityLen", None),
2616 _NTLMPayloadField(
2617 "Buffer",
2618 OFFSET,
2619 [
2620 PacketField("Security", None, GSSAPI_BLOB),
2621 ],
2622 ),
2623 ]
2624
2625 def __getattr__(self, attr):
2626 # Ease SMB1 backward compatibility
2627 if attr == "SecurityBlob":
2628 return (
2629 super(SMB2_Session_Setup_Response, self).__getattr__("Buffer")
2630 or [(None, None)]
2631 )[0][1]
2632 return super(SMB2_Session_Setup_Response, self).__getattr__(attr)
2633
2634 def setfieldval(self, attr, val):
2635 if attr == "SecurityBlob":
2636 return super(SMB2_Session_Setup_Response, self).setfieldval(
2637 "Buffer", [("Security", val)]
2638 )
2639 return super(SMB2_Session_Setup_Response, self).setfieldval(attr, val)
2640
2641 def post_build(self, pkt, pay):
2642 # type: (bytes, bytes) -> bytes
2643 return (
2644 _SMB2_post_build(
2645 self,
2646 pkt,
2647 self.OFFSET,
2648 {
2649 "Security": 4,
2650 },
2651 )
2652 + pay
2653 )
2654
2655
2656bind_top_down(
2657 SMB2_Header,
2658 SMB2_Session_Setup_Response,
2659 Command=0x0001,
2660 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2661)
2662
2663# sect 2.2.7
2664
2665
2666class SMB2_Session_Logoff_Request(_SMB2_Payload):
2667 name = "SMB2 LOGOFF Request"
2668 Command = 0x0002
2669 fields_desc = [
2670 XLEShortField("StructureSize", 0x4),
2671 ShortField("reserved", 0),
2672 ]
2673
2674
2675bind_top_down(
2676 SMB2_Header,
2677 SMB2_Session_Logoff_Request,
2678 Command=0x0002,
2679)
2680
2681# sect 2.2.8
2682
2683
2684class SMB2_Session_Logoff_Response(_SMB2_Payload):
2685 name = "SMB2 LOGOFF Request"
2686 Command = 0x0002
2687 fields_desc = [
2688 XLEShortField("StructureSize", 0x4),
2689 ShortField("reserved", 0),
2690 ]
2691
2692
2693bind_top_down(
2694 SMB2_Header,
2695 SMB2_Session_Logoff_Response,
2696 Command=0x0002,
2697 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
2698)
2699
2700# sect 2.2.9
2701
2702
2703class SMB2_Tree_Connect_Request(_SMB2_Payload, _NTLMPayloadPacket):
2704 name = "SMB2 TREE_CONNECT Request"
2705 Command = 0x0003
2706 OFFSET = 8 + 64
2707 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
2708 fields_desc = [
2709 XLEShortField("StructureSize", 0x9),
2710 FlagsField(
2711 "Flags",
2712 0,
2713 -16,
2714 ["CLUSTER_RECONNECT", "REDIRECT_TO_OWNER", "EXTENSION_PRESENT"],
2715 ),
2716 XLEShortField("PathBufferOffset", None),
2717 LEShortField("PathLen", None),
2718 _NTLMPayloadField(
2719 "Buffer",
2720 OFFSET,
2721 [
2722 StrFieldUtf16("Path", b""),
2723 ],
2724 ),
2725 ]
2726
2727 def post_build(self, pkt, pay):
2728 # type: (bytes, bytes) -> bytes
2729 return (
2730 _SMB2_post_build(
2731 self,
2732 pkt,
2733 self.OFFSET,
2734 {
2735 "Path": 4,
2736 },
2737 )
2738 + pay
2739 )
2740
2741
2742bind_top_down(
2743 SMB2_Header,
2744 SMB2_Tree_Connect_Request,
2745 Command=0x0003,
2746)
2747
2748# sect 2.2.10
2749
2750
2751class SMB2_Tree_Connect_Response(_SMB2_Payload):
2752 name = "SMB2 TREE_CONNECT Response"
2753 Command = 0x0003
2754 fields_desc = [
2755 XLEShortField("StructureSize", 0x10),
2756 ByteEnumField("ShareType", 0, {0x01: "DISK", 0x02: "PIPE", 0x03: "PRINT"}),
2757 ByteField("Reserved", 0),
2758 FlagsField(
2759 "ShareFlags",
2760 0x30,
2761 -32,
2762 {
2763 0x00000010: "AUTO_CACHING",
2764 0x00000020: "VDO_CACHING",
2765 0x00000030: "NO_CACHING",
2766 0x00000001: "DFS",
2767 0x00000002: "DFS_ROOT",
2768 0x00000100: "RESTRICT_EXCLUSIVE_OPENS",
2769 0x00000200: "FORCE_SHARED_DELETE",
2770 0x00000400: "ALLOW_NAMESPACE_CACHING",
2771 0x00000800: "ACCESS_BASED_DIRECTORY_ENUM",
2772 0x00001000: "FORCE_LEVELII_OPLOCK",
2773 0x00002000: "ENABLE_HASH_V1",
2774 0x00004000: "ENABLE_HASH_V2",
2775 0x00008000: "ENCRYPT_DATA",
2776 0x00040000: "IDENTITY_REMOTING",
2777 0x00100000: "COMPRESS_DATA",
2778 },
2779 ),
2780 FlagsField(
2781 "Capabilities",
2782 0,
2783 -32,
2784 {
2785 0x00000008: "DFS",
2786 0x00000010: "CONTINUOUS_AVAILABILITY",
2787 0x00000020: "SCALEOUT",
2788 0x00000040: "CLUSTER",
2789 0x00000080: "ASYMMETRIC",
2790 0x00000100: "REDIRECT_TO_OWNER",
2791 },
2792 ),
2793 FlagsField("MaximalAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
2794 ]
2795
2796
2797bind_top_down(SMB2_Header, SMB2_Tree_Connect_Response, Command=0x0003, Flags=1)
2798
2799# sect 2.2.11
2800
2801
2802class SMB2_Tree_Disconnect_Request(_SMB2_Payload):
2803 name = "SMB2 TREE_DISCONNECT Request"
2804 Command = 0x0004
2805 fields_desc = [
2806 XLEShortField("StructureSize", 0x4),
2807 XLEShortField("Reserved", 0),
2808 ]
2809
2810
2811bind_top_down(SMB2_Header, SMB2_Tree_Disconnect_Request, Command=0x0004)
2812
2813# sect 2.2.12
2814
2815
2816class SMB2_Tree_Disconnect_Response(_SMB2_Payload):
2817 name = "SMB2 TREE_DISCONNECT Response"
2818 Command = 0x0004
2819 fields_desc = [
2820 XLEShortField("StructureSize", 0x4),
2821 XLEShortField("Reserved", 0),
2822 ]
2823
2824
2825bind_top_down(SMB2_Header, SMB2_Tree_Disconnect_Response, Command=0x0004, Flags=1)
2826
2827
2828# sect 2.2.14.1
2829
2830
2831class SMB2_FILEID(Packet):
2832 fields_desc = [XLELongField("Persistent", 0), XLELongField("Volatile", 0)]
2833
2834 def __hash__(self):
2835 return self.Persistent + self.Volatile << 64
2836
2837 def default_payload_class(self, payload):
2838 return conf.padding_layer
2839
2840
2841# sect 2.2.14.2
2842
2843
2844class SMB2_CREATE_DURABLE_HANDLE_RESPONSE(Packet):
2845 fields_desc = [
2846 XStrFixedLenField("Reserved", b"\x00" * 8, length=8),
2847 ]
2848
2849
2850class SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE(Packet):
2851 fields_desc = [
2852 LEIntEnumField("QueryStatus", 0, STATUS_ERREF),
2853 FlagsField("MaximalAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
2854 ]
2855
2856
2857class SMB2_CREATE_QUERY_ON_DISK_ID(Packet):
2858 fields_desc = [
2859 XLELongField("DiskFileId", 0),
2860 XLELongField("VolumeId", 0),
2861 XStrFixedLenField("Reserved", b"", length=16),
2862 ]
2863
2864
2865class SMB2_CREATE_RESPONSE_LEASE(Packet):
2866 fields_desc = [
2867 UUIDField("LeaseKey", None),
2868 FlagsField(
2869 "LeaseState",
2870 0x7,
2871 -32,
2872 {
2873 0x01: "SMB2_LEASE_READ_CACHING",
2874 0x02: "SMB2_LEASE_HANDLE_CACHING",
2875 0x04: "SMB2_LEASE_WRITE_CACHING",
2876 },
2877 ),
2878 FlagsField(
2879 "LeaseFlags",
2880 0,
2881 -32,
2882 {
2883 0x02: "SMB2_LEASE_FLAG_BREAK_IN_PROGRESS",
2884 0x04: "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET",
2885 },
2886 ),
2887 LELongField("LeaseDuration", 0),
2888 ]
2889
2890
2891class SMB2_CREATE_RESPONSE_LEASE_V2(Packet):
2892 fields_desc = [
2893 SMB2_CREATE_RESPONSE_LEASE,
2894 UUIDField("ParentLeaseKey", None),
2895 LEShortField("Epoch", 0),
2896 LEShortField("Reserved", 0),
2897 ]
2898
2899
2900class SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2(Packet):
2901 fields_desc = [
2902 LEIntField("Timeout", 0),
2903 FlagsField(
2904 "Flags",
2905 0,
2906 -32,
2907 {
2908 0x02: "SMB2_DHANDLE_FLAG_PERSISTENT",
2909 },
2910 ),
2911 ]
2912
2913
2914# sect 2.2.13
2915
2916
2917class SMB2_CREATE_DURABLE_HANDLE_REQUEST(Packet):
2918 fields_desc = [
2919 XStrFixedLenField("DurableRequest", b"", length=16),
2920 ]
2921
2922
2923class SMB2_CREATE_DURABLE_HANDLE_RECONNECT(Packet):
2924 fields_desc = [
2925 PacketField("Data", SMB2_FILEID(), SMB2_FILEID),
2926 ]
2927
2928
2929class SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST(Packet):
2930 fields_desc = [
2931 LELongField("Timestamp", 0),
2932 ]
2933
2934
2935class SMB2_CREATE_ALLOCATION_SIZE(Packet):
2936 fields_desc = [
2937 LELongField("AllocationSize", 0),
2938 ]
2939
2940
2941class SMB2_CREATE_TIMEWARP_TOKEN(Packet):
2942 fields_desc = [
2943 LELongField("Timestamp", 0),
2944 ]
2945
2946
2947class SMB2_CREATE_REQUEST_LEASE(Packet):
2948 fields_desc = [
2949 SMB2_CREATE_RESPONSE_LEASE,
2950 ]
2951
2952
2953class SMB2_CREATE_REQUEST_LEASE_V2(Packet):
2954 fields_desc = [
2955 SMB2_CREATE_RESPONSE_LEASE_V2,
2956 ]
2957
2958
2959class SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2(Packet):
2960 fields_desc = [
2961 SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2,
2962 XStrFixedLenField("Reserved", b"", length=8),
2963 UUIDField("CreateGuid", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2964 ]
2965
2966
2967class SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2(Packet):
2968 fields_desc = [
2969 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
2970 UUIDField("CreateGuid", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
2971 FlagsField(
2972 "Flags",
2973 0,
2974 -32,
2975 {
2976 0x02: "SMB2_DHANDLE_FLAG_PERSISTENT",
2977 },
2978 ),
2979 ]
2980
2981
2982class SMB2_CREATE_APP_INSTANCE_ID(Packet):
2983 fields_desc = [
2984 XLEShortField("StructureSize", 0x14),
2985 LEShortField("Reserved", 0),
2986 XStrFixedLenField("AppInstanceId", b"", length=16),
2987 ]
2988
2989
2990class SMB2_CREATE_APP_INSTANCE_VERSION(Packet):
2991 fields_desc = [
2992 XLEShortField("StructureSize", 0x18),
2993 LEShortField("Reserved", 0),
2994 LEIntField("Padding", 0),
2995 LELongField("AppInstanceVersionHigh", 0),
2996 LELongField("AppInstanceVersionLow", 0),
2997 ]
2998
2999
3000class SMB2_Create_Context(_NTLMPayloadPacket):
3001 name = "SMB2 CREATE CONTEXT"
3002 OFFSET = 16
3003 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3004 fields_desc = [
3005 LEIntField("Next", None),
3006 XLEShortField("NameBufferOffset", None),
3007 LEShortField("NameLen", None),
3008 ShortField("Reserved", 0),
3009 XLEShortField("DataBufferOffset", None),
3010 LEIntField("DataLen", None),
3011 _NTLMPayloadField(
3012 "Buffer",
3013 OFFSET,
3014 [
3015 PadField(
3016 StrLenField("Name", b"", length_from=lambda pkt: pkt.NameLen),
3017 8,
3018 ),
3019 # Must be padded on 8-octet alignment
3020 PacketLenField(
3021 "Data", None, conf.raw_layer, length_from=lambda pkt: pkt.DataLen
3022 ),
3023 ],
3024 force_order=["Name", "Data"],
3025 ),
3026 StrLenField(
3027 "pad",
3028 b"",
3029 length_from=lambda x: (
3030 (
3031 x.Next
3032 - max(
3033 x.DataBufferOffset + x.DataLen, x.NameBufferOffset + x.NameLen
3034 )
3035 )
3036 if x.Next
3037 else 0
3038 ),
3039 ),
3040 ]
3041
3042 def post_dissect(self, s):
3043 if not self.DataLen:
3044 return s
3045 try:
3046 if isinstance(self.parent, SMB2_Create_Request):
3047 data_cls = {
3048 b"DHnQ": SMB2_CREATE_DURABLE_HANDLE_REQUEST,
3049 b"DHnC": SMB2_CREATE_DURABLE_HANDLE_RECONNECT,
3050 b"AISi": SMB2_CREATE_ALLOCATION_SIZE,
3051 b"MxAc": SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST,
3052 b"TWrp": SMB2_CREATE_TIMEWARP_TOKEN,
3053 b"QFid": SMB2_CREATE_QUERY_ON_DISK_ID,
3054 b"RqLs": SMB2_CREATE_REQUEST_LEASE,
3055 b"DH2Q": SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2,
3056 b"DH2C": SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2,
3057 # 3.1.1 only
3058 b"E\xbc\xa6j\xef\xa7\xf7J\x90\x08\xfaF.\x14Mt": SMB2_CREATE_APP_INSTANCE_ID, # noqa: E501
3059 b"\xb9\x82\xd0\xb7;V\x07O\xa0{RJ\x81\x16\xa0\x10": SMB2_CREATE_APP_INSTANCE_VERSION, # noqa: E501
3060 }[self.Name]
3061 if self.Name == b"RqLs" and self.DataLen > 32:
3062 data_cls = SMB2_CREATE_REQUEST_LEASE_V2
3063 elif isinstance(self.parent, SMB2_Create_Response):
3064 data_cls = {
3065 b"DHnQ": SMB2_CREATE_DURABLE_HANDLE_RESPONSE,
3066 b"MxAc": SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE,
3067 b"QFid": SMB2_CREATE_QUERY_ON_DISK_ID,
3068 b"RqLs": SMB2_CREATE_RESPONSE_LEASE,
3069 b"DH2Q": SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2,
3070 }[self.Name]
3071 if self.Name == b"RqLs" and self.DataLen > 32:
3072 data_cls = SMB2_CREATE_RESPONSE_LEASE_V2
3073 else:
3074 return s
3075 except KeyError:
3076 return s
3077 self.Data = data_cls(self.Data.load)
3078 return s
3079
3080 def default_payload_class(self, _):
3081 return conf.padding_layer
3082
3083 def post_build(self, pkt, pay):
3084 # type: (bytes, bytes) -> bytes
3085 return (
3086 _NTLM_post_build(
3087 self,
3088 pkt,
3089 self.OFFSET,
3090 {
3091 "Name": 4,
3092 "Data": 10,
3093 },
3094 config=[
3095 (
3096 "BufferOffset",
3097 {
3098 "Name": _NTLM_ENUM.OFFSET,
3099 "Data": _NTLM_ENUM.OFFSET | _NTLM_ENUM.PAD8,
3100 },
3101 ),
3102 ("Len", _NTLM_ENUM.LEN),
3103 ],
3104 )
3105 + pay
3106 )
3107
3108
3109# sect 2.2.13
3110
3111SMB2_OPLOCK_LEVELS = {
3112 0x00: "SMB2_OPLOCK_LEVEL_NONE",
3113 0x01: "SMB2_OPLOCK_LEVEL_II",
3114 0x08: "SMB2_OPLOCK_LEVEL_EXCLUSIVE",
3115 0x09: "SMB2_OPLOCK_LEVEL_BATCH",
3116 0xFF: "SMB2_OPLOCK_LEVEL_LEASE",
3117}
3118
3119
3120class SMB2_Create_Request(_SMB2_Payload, _NTLMPayloadPacket):
3121 name = "SMB2 CREATE Request"
3122 Command = 0x0005
3123 OFFSET = 56 + 64
3124 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3125 fields_desc = [
3126 XLEShortField("StructureSize", 0x39),
3127 ByteField("ShareType", 0),
3128 ByteEnumField("RequestedOplockLevel", 0, SMB2_OPLOCK_LEVELS),
3129 LEIntEnumField(
3130 "ImpersonationLevel",
3131 0,
3132 {
3133 0x00000000: "Anonymous",
3134 0x00000001: "Identification",
3135 0x00000002: "Impersonation",
3136 0x00000003: "Delegate",
3137 },
3138 ),
3139 LELongField("SmbCreateFlags", 0),
3140 LELongField("Reserved", 0),
3141 FlagsField("DesiredAccess", 0, -32, SMB2_ACCESS_FLAGS_FILE),
3142 FlagsField("FileAttributes", 0x00000080, -32, FileAttributes),
3143 FlagsField(
3144 "ShareAccess",
3145 0,
3146 -32,
3147 {
3148 0x00000001: "FILE_SHARE_READ",
3149 0x00000002: "FILE_SHARE_WRITE",
3150 0x00000004: "FILE_SHARE_DELETE",
3151 },
3152 ),
3153 LEIntEnumField(
3154 "CreateDisposition",
3155 1,
3156 {
3157 0x00000000: "FILE_SUPERSEDE",
3158 0x00000001: "FILE_OPEN",
3159 0x00000002: "FILE_CREATE",
3160 0x00000003: "FILE_OPEN_IF",
3161 0x00000004: "FILE_OVERWRITE",
3162 0x00000005: "FILE_OVERWRITE_IF",
3163 },
3164 ),
3165 FlagsField(
3166 "CreateOptions",
3167 0,
3168 -32,
3169 {
3170 0x00000001: "FILE_DIRECTORY_FILE",
3171 0x00000002: "FILE_WRITE_THROUGH",
3172 0x00000004: "FILE_SEQUENTIAL_ONLY",
3173 0x00000008: "FILE_NO_INTERMEDIATE_BUFFERING",
3174 0x00000010: "FILE_SYNCHRONOUS_IO_ALERT",
3175 0x00000020: "FILE_SYNCHRONOUS_IO_NONALERT",
3176 0x00000040: "FILE_NON_DIRECTORY_FILE",
3177 0x00000100: "FILE_COMPLETE_IF_OPLOCKED",
3178 0x00000200: "FILE_RANDOM_ACCESS",
3179 0x00001000: "FILE_DELETE_ON_CLOSE",
3180 0x00002000: "FILE_OPEN_BY_FILE_ID",
3181 0x00004000: "FILE_OPEN_FOR_BACKUP_INTENT",
3182 0x00008000: "FILE_NO_COMPRESSION",
3183 0x00000400: "FILE_OPEN_REMOTE_INSTANCE",
3184 0x00010000: "FILE_OPEN_REQUIRING_OPLOCK",
3185 0x00020000: "FILE_DISALLOW_EXCLUSIVE",
3186 0x00100000: "FILE_RESERVE_OPFILTER",
3187 0x00200000: "FILE_OPEN_REPARSE_POINT",
3188 0x00400000: "FILE_OPEN_NO_RECALL",
3189 0x00800000: "FILE_OPEN_FOR_FREE_SPACE_QUERY",
3190 },
3191 ),
3192 XLEShortField("NameBufferOffset", None),
3193 LEShortField("NameLen", None),
3194 XLEIntField("CreateContextsBufferOffset", None),
3195 LEIntField("CreateContextsLen", None),
3196 _NTLMPayloadField(
3197 "Buffer",
3198 OFFSET,
3199 [
3200 StrFieldUtf16("Name", b""),
3201 _NextPacketListField(
3202 "CreateContexts",
3203 [],
3204 SMB2_Create_Context,
3205 length_from=lambda pkt: pkt.CreateContextsLen,
3206 ),
3207 ],
3208 ),
3209 ]
3210
3211 def post_build(self, pkt, pay):
3212 # type: (bytes, bytes) -> bytes
3213 if len(pkt) == 0x38:
3214 # 'In the request, the Buffer field MUST be at least one byte in length.'
3215 pkt += b"\x00"
3216 return (
3217 _SMB2_post_build(
3218 self,
3219 pkt,
3220 self.OFFSET,
3221 {
3222 "Name": 44,
3223 "CreateContexts": 48,
3224 },
3225 )
3226 + pay
3227 )
3228
3229
3230bind_top_down(SMB2_Header, SMB2_Create_Request, Command=0x0005)
3231
3232
3233# sect 2.2.14
3234
3235
3236class SMB2_Create_Response(_SMB2_Payload, _NTLMPayloadPacket):
3237 name = "SMB2 CREATE Response"
3238 Command = 0x0005
3239 OFFSET = 88 + 64
3240 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3241 fields_desc = [
3242 XLEShortField("StructureSize", 0x59),
3243 ByteEnumField("OplockLevel", 0, SMB2_OPLOCK_LEVELS),
3244 FlagsField("Flags", 0, -8, {0x01: "SMB2_CREATE_FLAG_REPARSEPOINT"}),
3245 LEIntEnumField(
3246 "CreateAction",
3247 1,
3248 {
3249 0x00000000: "FILE_SUPERSEDED",
3250 0x00000001: "FILE_OPENED",
3251 0x00000002: "FILE_CREATED",
3252 0x00000003: "FILE_OVERWRITEN",
3253 },
3254 ),
3255 FileNetworkOpenInformation,
3256 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3257 XLEIntField("CreateContextsBufferOffset", None),
3258 LEIntField("CreateContextsLen", None),
3259 _NTLMPayloadField(
3260 "Buffer",
3261 OFFSET,
3262 [
3263 _NextPacketListField(
3264 "CreateContexts",
3265 [],
3266 SMB2_Create_Context,
3267 length_from=lambda pkt: pkt.CreateContextsLen,
3268 ),
3269 ],
3270 ),
3271 ]
3272
3273 def post_build(self, pkt, pay):
3274 # type: (bytes, bytes) -> bytes
3275 return (
3276 _SMB2_post_build(
3277 self,
3278 pkt,
3279 self.OFFSET,
3280 {
3281 "CreateContexts": 80,
3282 },
3283 )
3284 + pay
3285 )
3286
3287
3288bind_top_down(SMB2_Header, SMB2_Create_Response, Command=0x0005, Flags=1)
3289
3290# sect 2.2.15
3291
3292
3293class SMB2_Close_Request(_SMB2_Payload):
3294 name = "SMB2 CLOSE Request"
3295 Command = 0x0006
3296 fields_desc = [
3297 XLEShortField("StructureSize", 0x18),
3298 FlagsField("Flags", 0, -16, ["SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB"]),
3299 LEIntField("Reserved", 0),
3300 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3301 ]
3302
3303
3304bind_top_down(
3305 SMB2_Header,
3306 SMB2_Close_Request,
3307 Command=0x0006,
3308)
3309
3310# sect 2.2.16
3311
3312
3313class SMB2_Close_Response(_SMB2_Payload):
3314 name = "SMB2 CLOSE Response"
3315 Command = 0x0006
3316 FileAttributes = 0
3317 CreationTime = 0
3318 LastAccessTime = 0
3319 LastWriteTime = 0
3320 ChangeTime = 0
3321 fields_desc = [
3322 XLEShortField("StructureSize", 0x3C),
3323 FlagsField("Flags", 0, -16, ["SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB"]),
3324 LEIntField("Reserved", 0),
3325 ] + FileNetworkOpenInformation.fields_desc[:7]
3326
3327
3328bind_top_down(
3329 SMB2_Header,
3330 SMB2_Close_Response,
3331 Command=0x0006,
3332 Flags=1,
3333)
3334
3335# sect 2.2.19
3336
3337
3338class SMB2_Read_Request(_SMB2_Payload, _NTLMPayloadPacket):
3339 name = "SMB2 READ Request"
3340 Command = 0x0008
3341 OFFSET = 48 + 64
3342 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3343 fields_desc = [
3344 XLEShortField("StructureSize", 0x31),
3345 ByteField("Padding", 0x00),
3346 FlagsField(
3347 "Flags",
3348 0,
3349 -8,
3350 {
3351 0x01: "SMB2_READFLAG_READ_UNBUFFERED",
3352 0x02: "SMB2_READFLAG_REQUEST_COMPRESSED",
3353 },
3354 ),
3355 LEIntField("Length", 4280),
3356 LELongField("Offset", 0),
3357 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3358 LEIntField("MinimumCount", 0),
3359 LEIntEnumField(
3360 "Channel",
3361 0,
3362 {
3363 0x00000000: "SMB2_CHANNEL_NONE",
3364 0x00000001: "SMB2_CHANNEL_RDMA_V1",
3365 0x00000002: "SMB2_CHANNEL_RDMA_V1_INVALIDATE",
3366 0x00000003: "SMB2_CHANNEL_RDMA_TRANSFORM",
3367 },
3368 ),
3369 LEIntField("RemainingBytes", 0),
3370 LEShortField("ReadChannelInfoBufferOffset", None),
3371 LEShortField("ReadChannelInfoLen", None),
3372 _NTLMPayloadField(
3373 "Buffer",
3374 OFFSET,
3375 [
3376 StrLenField(
3377 "ReadChannelInfo",
3378 b"",
3379 length_from=lambda pkt: pkt.ReadChannelInfoLen,
3380 )
3381 ],
3382 ),
3383 ]
3384
3385 def post_build(self, pkt, pay):
3386 # type: (bytes, bytes) -> bytes
3387 if len(pkt) == 0x30:
3388 # 'The first byte of the Buffer field MUST be set to 0.'
3389 pkt += b"\x00"
3390 return (
3391 _SMB2_post_build(
3392 self,
3393 pkt,
3394 self.OFFSET,
3395 {
3396 "ReadChannelInfo": 44,
3397 },
3398 )
3399 + pay
3400 )
3401
3402
3403bind_top_down(
3404 SMB2_Header,
3405 SMB2_Read_Request,
3406 Command=0x0008,
3407)
3408
3409# sect 2.2.20
3410
3411
3412class SMB2_Read_Response(_SMB2_Payload, _NTLMPayloadPacket):
3413 name = "SMB2 READ Response"
3414 Command = 0x0008
3415 OFFSET = 16 + 64
3416 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3417 fields_desc = [
3418 XLEShortField("StructureSize", 0x11),
3419 LEShortField("DataBufferOffset", None),
3420 LEIntField("DataLen", None),
3421 LEIntField("DataRemaining", 0),
3422 FlagsField(
3423 "Flags",
3424 0,
3425 -32,
3426 {
3427 0x01: "SMB2_READFLAG_RESPONSE_RDMA_TRANSFORM",
3428 },
3429 ),
3430 _NTLMPayloadField(
3431 "Buffer",
3432 OFFSET,
3433 [StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen)],
3434 ),
3435 ]
3436
3437 def post_build(self, pkt, pay):
3438 # type: (bytes, bytes) -> bytes
3439 return (
3440 _SMB2_post_build(
3441 self,
3442 pkt,
3443 self.OFFSET,
3444 {
3445 "Data": 2,
3446 },
3447 )
3448 + pay
3449 )
3450
3451
3452bind_top_down(
3453 SMB2_Header,
3454 SMB2_Read_Response,
3455 Command=0x0008,
3456 Flags=1,
3457)
3458
3459
3460# sect 2.2.21
3461
3462
3463class SMB2_Write_Request(_SMB2_Payload, _NTLMPayloadPacket):
3464 name = "SMB2 WRITE Request"
3465 Command = 0x0009
3466 OFFSET = 48 + 64
3467 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3468 fields_desc = [
3469 XLEShortField("StructureSize", 0x31),
3470 LEShortField("DataBufferOffset", None),
3471 LEIntField("DataLen", None),
3472 LELongField("Offset", 0),
3473 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3474 LEIntEnumField(
3475 "Channel",
3476 0,
3477 {
3478 0x00000000: "SMB2_CHANNEL_NONE",
3479 0x00000001: "SMB2_CHANNEL_RDMA_V1",
3480 0x00000002: "SMB2_CHANNEL_RDMA_V1_INVALIDATE",
3481 0x00000003: "SMB2_CHANNEL_RDMA_TRANSFORM",
3482 },
3483 ),
3484 LEIntField("RemainingBytes", 0),
3485 LEShortField("WriteChannelInfoBufferOffset", None),
3486 LEShortField("WriteChannelInfoLen", None),
3487 FlagsField(
3488 "Flags",
3489 0,
3490 -32,
3491 {
3492 0x00000001: "SMB2_WRITEFLAG_WRITE_THROUGH",
3493 0x00000002: "SMB2_WRITEFLAG_WRITE_UNBUFFERED",
3494 },
3495 ),
3496 _NTLMPayloadField(
3497 "Buffer",
3498 OFFSET,
3499 [
3500 StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen),
3501 StrLenField(
3502 "WriteChannelInfo",
3503 b"",
3504 length_from=lambda pkt: pkt.WriteChannelInfoLen,
3505 ),
3506 ],
3507 ),
3508 ]
3509
3510 def post_build(self, pkt, pay):
3511 # type: (bytes, bytes) -> bytes
3512 return (
3513 _SMB2_post_build(
3514 self,
3515 pkt,
3516 self.OFFSET,
3517 {
3518 "Data": 2,
3519 "WriteChannelInfo": 40,
3520 },
3521 )
3522 + pay
3523 )
3524
3525
3526bind_top_down(
3527 SMB2_Header,
3528 SMB2_Write_Request,
3529 Command=0x0009,
3530)
3531
3532# sect 2.2.22
3533
3534
3535class SMB2_Write_Response(_SMB2_Payload):
3536 name = "SMB2 WRITE Response"
3537 Command = 0x0009
3538 fields_desc = [
3539 XLEShortField("StructureSize", 0x11),
3540 LEShortField("Reserved", 0),
3541 LEIntField("Count", 0),
3542 LEIntField("Remaining", 0),
3543 LEShortField("WriteChannelInfoBufferOffset", 0),
3544 LEShortField("WriteChannelInfoLen", 0),
3545 ]
3546
3547
3548bind_top_down(SMB2_Header, SMB2_Write_Response, Command=0x0009, Flags=1)
3549
3550# sect 2.2.28
3551
3552
3553class SMB2_Echo_Request(_SMB2_Payload):
3554 name = "SMB2 ECHO Request"
3555 Command = 0x000D
3556 fields_desc = [
3557 XLEShortField("StructureSize", 0x4),
3558 LEShortField("Reserved", 0),
3559 ]
3560
3561
3562bind_top_down(
3563 SMB2_Header,
3564 SMB2_Echo_Request,
3565 Command=0x000D,
3566)
3567
3568# sect 2.2.29
3569
3570
3571class SMB2_Echo_Response(_SMB2_Payload):
3572 name = "SMB2 ECHO Response"
3573 Command = 0x000D
3574 fields_desc = [
3575 XLEShortField("StructureSize", 0x4),
3576 LEShortField("Reserved", 0),
3577 ]
3578
3579
3580bind_top_down(
3581 SMB2_Header,
3582 SMB2_Echo_Response,
3583 Command=0x000D,
3584 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
3585)
3586
3587# sect 2.2.30
3588
3589
3590class SMB2_Cancel_Request(_SMB2_Payload):
3591 name = "SMB2 CANCEL Request"
3592 fields_desc = [
3593 XLEShortField("StructureSize", 0x4),
3594 LEShortField("Reserved", 0),
3595 ]
3596
3597
3598bind_top_down(
3599 SMB2_Header,
3600 SMB2_Cancel_Request,
3601 Command=0x0009,
3602)
3603
3604# sect 2.2.31.4
3605
3606
3607class SMB2_IOCTL_Validate_Negotiate_Info_Request(Packet):
3608 name = "SMB2 IOCTL Validate Negotiate Info"
3609 fields_desc = (
3610 SMB2_Negotiate_Protocol_Request.fields_desc[4:6]
3611 + SMB2_Negotiate_Protocol_Request.fields_desc[1:3][::-1] # Cap/GUID
3612 + [SMB2_Negotiate_Protocol_Request.fields_desc[9]] # SecMod/DC # Dialects
3613 )
3614
3615
3616# sect 2.2.31
3617
3618
3619class _SMB2_IOCTL_Request_PacketLenField(PacketLenField):
3620 def m2i(self, pkt, m):
3621 if pkt.CtlCode == 0x00140204: # FSCTL_VALIDATE_NEGOTIATE_INFO
3622 return SMB2_IOCTL_Validate_Negotiate_Info_Request(m)
3623 elif pkt.CtlCode == 0x00060194: # FSCTL_DFS_GET_REFERRALS
3624 return SMB2_IOCTL_REQ_GET_DFS_Referral(m)
3625 elif pkt.CtlCode == 0x00094264: # FSCTL_OFFLOAD_READ
3626 return SMB2_IOCTL_OFFLOAD_READ_Request(m)
3627 return conf.raw_layer(m)
3628
3629
3630class SMB2_IOCTL_Request(_SMB2_Payload, _NTLMPayloadPacket):
3631 name = "SMB2 IOCTL Request"
3632 Command = 0x000B
3633 OFFSET = 56 + 64
3634 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3635 deprecated_fields = {
3636 "IntputCount": ("InputLen", "alias"),
3637 "OutputCount": ("OutputLen", "alias"),
3638 }
3639 fields_desc = [
3640 XLEShortField("StructureSize", 0x39),
3641 LEShortField("Reserved", 0),
3642 LEIntEnumField(
3643 "CtlCode",
3644 0,
3645 {
3646 0x00060194: "FSCTL_DFS_GET_REFERRALS",
3647 0x0011400C: "FSCTL_PIPE_PEEK",
3648 0x00110018: "FSCTL_PIPE_WAIT",
3649 0x0011C017: "FSCTL_PIPE_TRANSCEIVE",
3650 0x001440F2: "FSCTL_SRV_COPYCHUNK",
3651 0x00144064: "FSCTL_SRV_ENUMERATE_SNAPSHOTS",
3652 0x00140078: "FSCTL_SRV_REQUEST_RESUME_KEY",
3653 0x001441BB: "FSCTL_SRV_READ_HASH",
3654 0x001480F2: "FSCTL_SRV_COPYCHUNK_WRITE",
3655 0x001401D4: "FSCTL_LMR_REQUEST_RESILIENCY",
3656 0x001401FC: "FSCTL_QUERY_NETWORK_INTERFACE_INFO",
3657 0x000900A4: "FSCTL_SET_REPARSE_POINT",
3658 0x000601B0: "FSCTL_DFS_GET_REFERRALS_EX",
3659 0x00098208: "FSCTL_FILE_LEVEL_TRIM",
3660 0x00140204: "FSCTL_VALIDATE_NEGOTIATE_INFO",
3661 0x00094264: "FSCTL_OFFLOAD_READ",
3662 },
3663 ),
3664 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3665 LEIntField("InputBufferOffset", None),
3666 LEIntField("InputLen", None), # Called InputCount but it's a length
3667 LEIntField("MaxInputResponse", 0),
3668 LEIntField("OutputBufferOffset", None),
3669 LEIntField("OutputLen", None), # Called OutputCount.
3670 LEIntField("MaxOutputResponse", 65535),
3671 FlagsField("Flags", 0, -32, {0x00000001: "SMB2_0_IOCTL_IS_FSCTL"}),
3672 LEIntField("Reserved2", 0),
3673 _NTLMPayloadField(
3674 "Buffer",
3675 OFFSET,
3676 [
3677 _SMB2_IOCTL_Request_PacketLenField(
3678 "Input", None, conf.raw_layer, length_from=lambda pkt: pkt.InputLen
3679 ),
3680 _SMB2_IOCTL_Request_PacketLenField(
3681 "Output",
3682 None,
3683 conf.raw_layer,
3684 length_from=lambda pkt: pkt.OutputLen,
3685 ),
3686 ],
3687 ),
3688 ]
3689
3690 def post_build(self, pkt, pay):
3691 # type: (bytes, bytes) -> bytes
3692 return (
3693 _SMB2_post_build(
3694 self,
3695 pkt,
3696 self.OFFSET,
3697 {
3698 "Input": 24,
3699 "Output": 36,
3700 },
3701 )
3702 + pay
3703 )
3704
3705
3706bind_top_down(
3707 SMB2_Header,
3708 SMB2_IOCTL_Request,
3709 Command=0x000B,
3710)
3711
3712# sect 2.2.32.5
3713
3714
3715class SOCKADDR_STORAGE(Packet):
3716 fields_desc = [
3717 LEShortEnumField("Family", 0x0002, {0x0002: "IPv4", 0x0017: "IPv6"}),
3718 ShortField("Port", 0),
3719 # IPv4
3720 ConditionalField(
3721 IPField("IPv4Adddress", None),
3722 lambda pkt: pkt.Family == 0x0002,
3723 ),
3724 ConditionalField(
3725 StrFixedLenField("Reserved", b"", length=8),
3726 lambda pkt: pkt.Family == 0x0002,
3727 ),
3728 # IPv6
3729 ConditionalField(
3730 LEIntField("FlowInfo", 0),
3731 lambda pkt: pkt.Family == 0x00017,
3732 ),
3733 ConditionalField(
3734 IP6Field("IPv6Address", None),
3735 lambda pkt: pkt.Family == 0x00017,
3736 ),
3737 ConditionalField(
3738 LEIntField("ScopeId", 0),
3739 lambda pkt: pkt.Family == 0x00017,
3740 ),
3741 ]
3742
3743 def default_payload_class(self, _):
3744 return conf.padding_layer
3745
3746
3747class NETWORK_INTERFACE_INFO(Packet):
3748 fields_desc = [
3749 LEIntField("Next", None), # 0 = no next entry
3750 LEIntField("IfIndex", 1),
3751 FlagsField(
3752 "Capability",
3753 1,
3754 -32,
3755 {
3756 0x00000001: "RSS_CAPABLE",
3757 0x00000002: "RDMA_CAPABLE",
3758 },
3759 ),
3760 LEIntField("Reserved", 0),
3761 ScalingField("LinkSpeed", 10000000000, fmt="<Q", unit="bit/s"),
3762 PacketField("SockAddr_Storage", SOCKADDR_STORAGE(), SOCKADDR_STORAGE),
3763 ]
3764
3765 def default_payload_class(self, _):
3766 return conf.padding_layer
3767
3768
3769class SMB2_IOCTL_Network_Interface_Info(Packet):
3770 name = "SMB2 IOCTL Network Interface Info response"
3771 fields_desc = [
3772 _NextPacketListField("interfaces", [], NETWORK_INTERFACE_INFO),
3773 ]
3774
3775
3776# sect 2.2.32.6
3777
3778
3779class SMB2_IOCTL_Validate_Negotiate_Info_Response(Packet):
3780 name = "SMB2 IOCTL Validate Negotiate Info"
3781 fields_desc = (
3782 SMB2_Negotiate_Protocol_Response.fields_desc[4:6][::-1]
3783 + SMB2_Negotiate_Protocol_Response.fields_desc[ # Cap/GUID
3784 1:3
3785 ] # SecMod/DialectRevision
3786 )
3787
3788
3789# [MS-FSCC] sect 2.3.42
3790
3791
3792class SMB2_IOCTL_OFFLOAD_READ_Request(Packet):
3793 name = "SMB2 IOCTL OFFLOAD_READ Request"
3794 fields_desc = [
3795 LEIntField("StructureSize", 0x20),
3796 LEIntField("Flags", 0),
3797 LEIntField("TokenTimeToLive", 0),
3798 LEIntField("Reserved", 0),
3799 LELongField("FileOffset", 0),
3800 LELongField("CopyLength", 0),
3801 ]
3802
3803
3804# [MS-FSCC] sect 2.1.11
3805
3806
3807class STORAGE_OFFLOAD_TOKEN(Packet):
3808 fields_desc = [
3809 LEIntEnumField(
3810 "TokenType",
3811 0xFFFF0001,
3812 {
3813 0xFFFF0001: "STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA",
3814 },
3815 ),
3816 LEShortField("Reserved", 0),
3817 FieldLenField("TokenIdLength", None, fmt="<H", length_of="TokenId"),
3818 StrFixedLenField("TokenId", b"", length=504),
3819 ]
3820
3821
3822# [MS-FSCC] sect 2.3.42
3823
3824
3825class SMB2_IOCTL_OFFLOAD_READ_Response(Packet):
3826 name = "SMB2 IOCTL OFFLOAD_READ Response"
3827 fields_desc = [
3828 LEIntField("StructureSize", 0x210),
3829 FlagsField(
3830 "Flags",
3831 0,
3832 -32,
3833 {
3834 0x00000001: "OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE",
3835 },
3836 ),
3837 LELongField("TransferLength", 0),
3838 PacketField("Token", STORAGE_OFFLOAD_TOKEN(), STORAGE_OFFLOAD_TOKEN),
3839 ]
3840
3841
3842# sect 2.2.32
3843
3844
3845class _SMB2_IOCTL_Response_PacketLenField(PacketLenField):
3846 def m2i(self, pkt, m):
3847 if pkt.CtlCode == 0x00140204: # FSCTL_VALIDATE_NEGOTIATE_INFO
3848 return SMB2_IOCTL_Validate_Negotiate_Info_Response(m)
3849 elif pkt.CtlCode == 0x001401FC: # FSCTL_QUERY_NETWORK_INTERFACE_INFO
3850 return SMB2_IOCTL_Network_Interface_Info(m)
3851 elif pkt.CtlCode == 0x00060194: # FSCTL_DFS_GET_REFERRALS
3852 return SMB2_IOCTL_RESP_GET_DFS_Referral(m)
3853 return conf.raw_layer(m)
3854
3855
3856class SMB2_IOCTL_Response(_SMB2_Payload, _NTLMPayloadPacket):
3857 name = "SMB2 IOCTL Response"
3858 Command = 0x000B
3859 OFFSET = 48 + 64
3860 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3861 StructureSize = 0x31
3862 MaxOutputResponse = 0
3863 fields_desc = (
3864 SMB2_IOCTL_Request.fields_desc[:6]
3865 + SMB2_IOCTL_Request.fields_desc[7:9]
3866 + SMB2_IOCTL_Request.fields_desc[10:12]
3867 + [
3868 _NTLMPayloadField(
3869 "Buffer",
3870 OFFSET,
3871 [
3872 _SMB2_IOCTL_Response_PacketLenField(
3873 "Input",
3874 None,
3875 conf.raw_layer,
3876 length_from=lambda pkt: pkt.InputLen,
3877 ),
3878 _SMB2_IOCTL_Response_PacketLenField(
3879 "Output",
3880 None,
3881 conf.raw_layer,
3882 length_from=lambda pkt: pkt.OutputLen,
3883 ),
3884 ],
3885 ),
3886 ]
3887 )
3888
3889 def post_build(self, pkt, pay):
3890 # type: (bytes, bytes) -> bytes
3891 return (
3892 _SMB2_post_build(
3893 self,
3894 pkt,
3895 self.OFFSET,
3896 {
3897 "Input": 24,
3898 "Output": 32,
3899 },
3900 )
3901 + pay
3902 )
3903
3904
3905bind_top_down(
3906 SMB2_Header,
3907 SMB2_IOCTL_Response,
3908 Command=0x000B,
3909 Flags=1, # SMB2_FLAGS_SERVER_TO_REDIR
3910)
3911
3912# sect 2.2.33
3913
3914
3915class SMB2_Query_Directory_Request(_SMB2_Payload, _NTLMPayloadPacket):
3916 name = "SMB2 QUERY DIRECTORY Request"
3917 Command = 0x000E
3918 OFFSET = 32 + 64
3919 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3920 fields_desc = [
3921 XLEShortField("StructureSize", 0x21),
3922 ByteEnumField("FileInformationClass", 0x1, FileInformationClasses),
3923 FlagsField(
3924 "Flags",
3925 0,
3926 -8,
3927 {
3928 0x01: "SMB2_RESTART_SCANS",
3929 0x02: "SMB2_RETURN_SINGLE_ENTRY",
3930 0x04: "SMB2_INDEX_SPECIFIED",
3931 0x10: "SMB2_REOPEN",
3932 },
3933 ),
3934 LEIntField("FileIndex", 0),
3935 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
3936 LEShortField("FileNameBufferOffset", None),
3937 LEShortField("FileNameLen", None),
3938 LEIntField("OutputBufferLength", 65535),
3939 _NTLMPayloadField("Buffer", OFFSET, [StrFieldUtf16("FileName", b"")]),
3940 ]
3941
3942 def post_build(self, pkt, pay):
3943 # type: (bytes, bytes) -> bytes
3944 return (
3945 _SMB2_post_build(
3946 self,
3947 pkt,
3948 self.OFFSET,
3949 {
3950 "FileName": 24,
3951 },
3952 )
3953 + pay
3954 )
3955
3956
3957bind_top_down(
3958 SMB2_Header,
3959 SMB2_Query_Directory_Request,
3960 Command=0x000E,
3961)
3962
3963# sect 2.2.34
3964
3965
3966class SMB2_Query_Directory_Response(_SMB2_Payload, _NTLMPayloadPacket):
3967 name = "SMB2 QUERY DIRECTORY Response"
3968 Command = 0x000E
3969 OFFSET = 8 + 64
3970 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
3971 fields_desc = [
3972 XLEShortField("StructureSize", 0x9),
3973 LEShortField("OutputBufferOffset", None),
3974 LEIntField("OutputLen", None),
3975 _NTLMPayloadField(
3976 "Buffer",
3977 OFFSET,
3978 [
3979 # TODO
3980 StrFixedLenField("Output", b"", length_from=lambda pkt: pkt.OutputLen)
3981 ],
3982 ),
3983 ]
3984
3985 def post_build(self, pkt, pay):
3986 # type: (bytes, bytes) -> bytes
3987 return (
3988 _SMB2_post_build(
3989 self,
3990 pkt,
3991 self.OFFSET,
3992 {
3993 "Output": 2,
3994 },
3995 )
3996 + pay
3997 )
3998
3999
4000bind_top_down(
4001 SMB2_Header,
4002 SMB2_Query_Directory_Response,
4003 Command=0x000E,
4004 Flags=1,
4005)
4006
4007# sect 2.2.35
4008
4009
4010class SMB2_Change_Notify_Request(_SMB2_Payload):
4011 name = "SMB2 CHANGE NOTIFY Request"
4012 Command = 0x000F
4013 fields_desc = [
4014 XLEShortField("StructureSize", 0x20),
4015 FlagsField(
4016 "Flags",
4017 0,
4018 -16,
4019 {
4020 0x0001: "SMB2_WATCH_TREE",
4021 },
4022 ),
4023 LEIntField("OutputBufferLength", 2048),
4024 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
4025 FlagsField(
4026 "CompletionFilter",
4027 0,
4028 -32,
4029 {
4030 0x00000001: "FILE_NOTIFY_CHANGE_FILE_NAME",
4031 0x00000002: "FILE_NOTIFY_CHANGE_DIR_NAME",
4032 0x00000004: "FILE_NOTIFY_CHANGE_ATTRIBUTES",
4033 0x00000008: "FILE_NOTIFY_CHANGE_SIZE",
4034 0x00000010: "FILE_NOTIFY_CHANGE_LAST_WRITE",
4035 0x00000020: "FILE_NOTIFY_CHANGE_LAST_ACCESS",
4036 0x00000040: "FILE_NOTIFY_CHANGE_CREATION",
4037 0x00000080: "FILE_NOTIFY_CHANGE_EA",
4038 0x00000100: "FILE_NOTIFY_CHANGE_SECURITY",
4039 0x00000200: "FILE_NOTIFY_CHANGE_STREAM_NAME",
4040 0x00000400: "FILE_NOTIFY_CHANGE_STREAM_SIZE",
4041 0x00000800: "FILE_NOTIFY_CHANGE_STREAM_WRITE",
4042 },
4043 ),
4044 LEIntField("Reserved", 0),
4045 ]
4046
4047
4048bind_top_down(
4049 SMB2_Header,
4050 SMB2_Change_Notify_Request,
4051 Command=0x000F,
4052)
4053
4054# sect 2.2.36
4055
4056
4057class SMB2_Change_Notify_Response(_SMB2_Payload, _NTLMPayloadPacket):
4058 name = "SMB2 CHANGE NOTIFY Response"
4059 Command = 0x000F
4060 OFFSET = 8 + 64
4061 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
4062 fields_desc = [
4063 XLEShortField("StructureSize", 0x9),
4064 LEShortField("OutputBufferOffset", None),
4065 LEIntField("OutputLen", None),
4066 _NTLMPayloadField(
4067 "Buffer",
4068 OFFSET,
4069 [
4070 _NextPacketListField(
4071 "Output",
4072 [],
4073 FILE_NOTIFY_INFORMATION,
4074 length_from=lambda pkt: pkt.OutputLen,
4075 max_count=1000,
4076 )
4077 ],
4078 ),
4079 ]
4080
4081 def post_build(self, pkt, pay):
4082 # type: (bytes, bytes) -> bytes
4083 return (
4084 _SMB2_post_build(
4085 self,
4086 pkt,
4087 self.OFFSET,
4088 {
4089 "Output": 2,
4090 },
4091 )
4092 + pay
4093 )
4094
4095
4096bind_top_down(
4097 SMB2_Header,
4098 SMB2_Change_Notify_Response,
4099 Command=0x000F,
4100 Flags=1,
4101)
4102
4103# sect 2.2.37
4104
4105
4106class FILE_GET_QUOTA_INFORMATION(Packet):
4107 fields_desc = [
4108 IntField("NextEntryOffset", 0),
4109 FieldLenField("SidLength", None, length_of="Sid"),
4110 StrLenField("Sid", b"", length_from=lambda x: x.SidLength),
4111 StrLenField(
4112 "pad",
4113 b"",
4114 length_from=lambda x: (
4115 (x.NextEntryOffset - x.SidLength) if x.NextEntryOffset else 0
4116 ),
4117 ),
4118 ]
4119
4120
4121class SMB2_Query_Quota_Info(Packet):
4122 fields_desc = [
4123 ByteField("ReturnSingle", 0),
4124 ByteField("ReturnBoolean", 0),
4125 ShortField("Reserved", 0),
4126 LEIntField("SidListLength", 0),
4127 LEIntField("StartSidLength", 0),
4128 LEIntField("StartSidOffset", 0),
4129 StrLenField("pad", b"", length_from=lambda x: x.StartSidOffset),
4130 MultipleTypeField(
4131 [
4132 (
4133 PacketListField(
4134 "SidBuffer",
4135 [],
4136 FILE_GET_QUOTA_INFORMATION,
4137 length_from=lambda x: x.SidListLength,
4138 ),
4139 lambda x: x.SidListLength,
4140 ),
4141 (
4142 StrLenField(
4143 "SidBuffer", b"", length_from=lambda x: x.StartSidLength
4144 ),
4145 lambda x: x.StartSidLength,
4146 ),
4147 ],
4148 StrFixedLenField("SidBuffer", b"", length=0),
4149 ),
4150 ]
4151
4152
4153SMB2_INFO_TYPE = {
4154 0x01: "SMB2_0_INFO_FILE",
4155 0x02: "SMB2_0_INFO_FILESYSTEM",
4156 0x03: "SMB2_0_INFO_SECURITY",
4157 0x04: "SMB2_0_INFO_QUOTA",
4158}
4159
4160SMB2_ADDITIONAL_INFORMATION = {
4161 0x00000001: "OWNER_SECURITY_INFORMATION",
4162 0x00000002: "GROUP_SECURITY_INFORMATION",
4163 0x00000004: "DACL_SECURITY_INFORMATION",
4164 0x00000008: "SACL_SECURITY_INFORMATION",
4165 0x00000010: "LABEL_SECURITY_INFORMATION",
4166 0x00000020: "ATTRIBUTE_SECURITY_INFORMATION",
4167 0x00000040: "SCOPE_SECURITY_INFORMATION",
4168 0x00010000: "BACKUP_SECURITY_INFORMATION",
4169}
4170
4171
4172class SMB2_Query_Info_Request(_SMB2_Payload, _NTLMPayloadPacket):
4173 name = "SMB2 QUERY INFO Request"
4174 Command = 0x0010
4175 OFFSET = 40 + 64
4176 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
4177 fields_desc = [
4178 XLEShortField("StructureSize", 0x29),
4179 ByteEnumField(
4180 "InfoType",
4181 0,
4182 SMB2_INFO_TYPE,
4183 ),
4184 ByteEnumField("FileInfoClass", 0, FileInformationClasses),
4185 LEIntField("OutputBufferLength", 0),
4186 XLEIntField("InputBufferOffset", None), # Short + Reserved = Int
4187 LEIntField("InputLen", None),
4188 FlagsField(
4189 "AdditionalInformation",
4190 0,
4191 -32,
4192 SMB2_ADDITIONAL_INFORMATION,
4193 ),
4194 FlagsField(
4195 "Flags",
4196 0,
4197 -32,
4198 {
4199 0x00000001: "SL_RESTART_SCAN",
4200 0x00000002: "SL_RETURN_SINGLE_ENTRY",
4201 0x00000004: "SL_INDEX_SPECIFIED",
4202 },
4203 ),
4204 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
4205 _NTLMPayloadField(
4206 "Buffer",
4207 OFFSET,
4208 [
4209 MultipleTypeField(
4210 [
4211 (
4212 # QUOTA
4213 PacketListField(
4214 "Input",
4215 None,
4216 SMB2_Query_Quota_Info,
4217 length_from=lambda pkt: pkt.InputLen,
4218 ),
4219 lambda pkt: pkt.InfoType == 0x04,
4220 ),
4221 ],
4222 StrLenField("Input", b"", length_from=lambda pkt: pkt.InputLen),
4223 ),
4224 ],
4225 ),
4226 ]
4227
4228 def post_build(self, pkt, pay):
4229 # type: (bytes, bytes) -> bytes
4230 return (
4231 _SMB2_post_build(
4232 self,
4233 pkt,
4234 self.OFFSET,
4235 {
4236 "Input": 4,
4237 },
4238 )
4239 + pay
4240 )
4241
4242
4243bind_top_down(
4244 SMB2_Header,
4245 SMB2_Query_Info_Request,
4246 Command=0x00010,
4247)
4248
4249
4250class SMB2_Query_Info_Response(_SMB2_Payload, _NTLMPayloadPacket):
4251 name = "SMB2 QUERY INFO Response"
4252 Command = 0x0010
4253 OFFSET = 8 + 64
4254 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
4255 fields_desc = [
4256 XLEShortField("StructureSize", 0x9),
4257 LEShortField("OutputBufferOffset", None),
4258 LEIntField("OutputLen", None),
4259 _NTLMPayloadField(
4260 "Buffer",
4261 OFFSET,
4262 [
4263 # TODO
4264 StrFixedLenField("Output", b"", length_from=lambda pkt: pkt.OutputLen)
4265 ],
4266 ),
4267 ]
4268
4269 def post_build(self, pkt, pay):
4270 # type: (bytes, bytes) -> bytes
4271 return (
4272 _SMB2_post_build(
4273 self,
4274 pkt,
4275 self.OFFSET,
4276 {
4277 "Output": 2,
4278 },
4279 )
4280 + pay
4281 )
4282
4283
4284bind_top_down(
4285 SMB2_Header,
4286 SMB2_Query_Info_Response,
4287 Command=0x00010,
4288 Flags=1,
4289)
4290
4291
4292# sect 2.2.39
4293
4294
4295class SMB2_Set_Info_Request(_SMB2_Payload, _NTLMPayloadPacket):
4296 name = "SMB2 SET INFO Request"
4297 Command = 0x0011
4298 OFFSET = 32 + 64
4299 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
4300 fields_desc = [
4301 XLEShortField("StructureSize", 0x21),
4302 ByteEnumField(
4303 "InfoType",
4304 0,
4305 SMB2_INFO_TYPE,
4306 ),
4307 ByteEnumField("FileInfoClass", 0, FileInformationClasses),
4308 LEIntField("DataLen", None),
4309 XLEIntField("DataBufferOffset", None), # Short + Reserved = Int
4310 FlagsField(
4311 "AdditionalInformation",
4312 0,
4313 -32,
4314 SMB2_ADDITIONAL_INFORMATION,
4315 ),
4316 PacketField("FileId", SMB2_FILEID(), SMB2_FILEID),
4317 _NTLMPayloadField(
4318 "Buffer",
4319 OFFSET,
4320 [
4321 MultipleTypeField(
4322 [
4323 (
4324 # FILE
4325 PacketLenField(
4326 "Data",
4327 None,
4328 lambda x, _parent: _FileInformationClasses.get(
4329 _parent.FileInfoClass, conf.raw_layer
4330 )(x),
4331 length_from=lambda pkt: pkt.DataLen,
4332 ),
4333 lambda pkt: pkt.InfoType == 0x01,
4334 ),
4335 (
4336 # QUOTA
4337 PacketListField(
4338 "Data",
4339 None,
4340 SMB2_Query_Quota_Info,
4341 length_from=lambda pkt: pkt.DataLen,
4342 ),
4343 lambda pkt: pkt.InfoType == 0x04,
4344 ),
4345 ],
4346 StrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen),
4347 ),
4348 ],
4349 ),
4350 ]
4351
4352 def post_build(self, pkt, pay):
4353 # type: (bytes, bytes) -> bytes
4354 return (
4355 _SMB2_post_build(
4356 self,
4357 pkt,
4358 self.OFFSET,
4359 {
4360 "Data": 4,
4361 },
4362 )
4363 + pay
4364 )
4365
4366
4367bind_top_down(
4368 SMB2_Header,
4369 SMB2_Set_Info_Request,
4370 Command=0x00011,
4371)
4372
4373
4374class SMB2_Set_Info_Response(_SMB2_Payload):
4375 name = "SMB2 SET INFO Request"
4376 Command = 0x0011
4377 fields_desc = [
4378 XLEShortField("StructureSize", 0x02),
4379 ]
4380
4381
4382bind_top_down(
4383 SMB2_Header,
4384 SMB2_Set_Info_Response,
4385 Command=0x00011,
4386 Flags=1,
4387)
4388
4389
4390# sect 2.2.41
4391
4392
4393class SMB2_Transform_Header(Packet):
4394 name = "SMB2 Transform Header"
4395 fields_desc = [
4396 StrFixedLenField("Start", b"\xfdSMB", 4),
4397 XStrFixedLenField("Signature", 0, length=16),
4398 XStrFixedLenField("Nonce", b"", length=16),
4399 LEIntField("OriginalMessageSize", 0x0),
4400 LEShortField("Reserved", 0),
4401 LEShortEnumField(
4402 "Flags",
4403 0x1,
4404 {
4405 0x0001: "ENCRYPTED",
4406 },
4407 ),
4408 LELongField("SessionId", 0),
4409 ]
4410
4411 def decrypt(self, dialect, DecryptionKey, CipherId):
4412 """
4413 [MS-SMB2] sect 3.2.5.1.1.1 - Decrypting the Message
4414 """
4415 if not isinstance(self.payload, conf.raw_layer):
4416 raise Exception("No payload to decrypt !")
4417
4418 if "GCM" in CipherId:
4419 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
4420
4421 nonce = self.Nonce[:12]
4422 cipher = AESGCM(DecryptionKey)
4423 elif "CCM" in CipherId:
4424 from cryptography.hazmat.primitives.ciphers.aead import AESCCM
4425
4426 nonce = self.Nonce[:11]
4427 cipher = AESCCM(DecryptionKey)
4428 else:
4429 raise Exception("Unknown CipherId !")
4430
4431 # Decrypt the data
4432 aad = self.self_build()[20:]
4433 data = cipher.decrypt(
4434 nonce,
4435 self.payload.load + self.Signature,
4436 aad,
4437 )
4438 return SMB2_Header(data, _decrypted=True)
4439
4440
4441bind_layers(SMB2_Transform_Header, conf.raw_layer)
4442
4443
4444# sect 2.2.42.1
4445
4446
4447class SMB2_Compression_Transform_Header(Packet):
4448 name = "SMB2 Compression Transform Header"
4449 fields_desc = [
4450 StrFixedLenField("Start", b"\xfcSMB", 4),
4451 LEIntField("OriginalCompressedSegmentSize", 0x0),
4452 LEShortEnumField("CompressionAlgorithm", 0, SMB2_COMPRESSION_ALGORITHMS),
4453 LEShortEnumField(
4454 "Flags",
4455 0x0,
4456 {
4457 0x0000: "SMB2_COMPRESSION_FLAG_NONE",
4458 0x0001: "SMB2_COMPRESSION_FLAG_CHAINED",
4459 },
4460 ),
4461 XLEIntField("Offset_or_Length", 0),
4462 ]
4463
4464
4465# [MS-DFSC] sect 2.2
4466
4467
4468class SMB2_IOCTL_REQ_GET_DFS_Referral(Packet):
4469 fields_desc = [
4470 LEShortField("MaxReferralLevel", 0),
4471 StrNullFieldUtf16("RequestFileName", ""),
4472 ]
4473
4474
4475class DFS_REFERRAL(Packet):
4476 fields_desc = [
4477 LEShortField("Version", 1),
4478 FieldLenField(
4479 "Size", None, fmt="<H", length_of="ShareName", adjust=lambda pkt, x: x + 9
4480 ),
4481 LEShortEnumField("ServerType", 0, {0: "non-root", 1: "root"}),
4482 LEShortField("ReferralEntryFlags", 0),
4483 StrNullFieldUtf16("ShareName", ""),
4484 ]
4485
4486 @classmethod
4487 def dispatch_hook(cls, _pkt=None, *args, **kargs):
4488 if _pkt and len(_pkt) >= 2:
4489 version = struct.unpack("<H", _pkt[:2])[0]
4490 if version == 1:
4491 return DFS_REFERRAL
4492 elif version == 3:
4493 return DFS_REFERRAL_V3
4494 elif version == 4:
4495 return DFS_REFERRAL_V4
4496 return cls
4497
4498 def default_payload_class(self, s):
4499 return conf.padding_layer
4500
4501
4502class DFS_REFERRAL_V3(DFS_REFERRAL):
4503 fields_desc = [
4504 LEShortField("Version", 3),
4505 LEShortField("Size", None),
4506 LEShortEnumField("ServerType", 0, {0: "non-root", 1: "root"}),
4507 FlagsField(
4508 "ReferralEntryFlags",
4509 0,
4510 -16,
4511 {
4512 0x0002: "NameListReferral",
4513 0x0004: "TargetSetBoundary",
4514 },
4515 ),
4516 LEIntField("TimeToLive", 300),
4517 # NameListReferral is 0
4518 ConditionalField(
4519 LEShortField("DFSPathOffset", None),
4520 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4521 ),
4522 ConditionalField(
4523 LEShortField("DFSAlternatePathOffset", None),
4524 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4525 ),
4526 ConditionalField(
4527 LEShortField("NetworkAddressOffset", None),
4528 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4529 ),
4530 ConditionalField(
4531 StrFixedLenField("ServiceSiteGuid", 0, length=16),
4532 lambda pkt: not pkt.ReferralEntryFlags.NameListReferral,
4533 ),
4534 # NameListReferral is 1
4535 ConditionalField(
4536 LEShortField("SpecialNameOffset", None),
4537 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4538 ),
4539 ConditionalField(
4540 LEShortField("NumberOfExpandedNames", None),
4541 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4542 ),
4543 ConditionalField(
4544 LEShortField("ExpandedNameOffset", None),
4545 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4546 ),
4547 ConditionalField(
4548 StrLenField("Padding", None, length_from=lambda pkt: pkt.Size - 18),
4549 lambda pkt: pkt.ReferralEntryFlags.NameListReferral,
4550 ),
4551 ]
4552
4553 def post_build(self, pkt, pay):
4554 # type: (bytes, bytes) -> bytes
4555 if self.Size is None:
4556 pkt = pkt[:2] + struct.pack("<H", len(pkt)) + pkt[4:]
4557 return pkt + pay
4558
4559
4560class DFS_REFERRAL_V4(DFS_REFERRAL_V3):
4561 Version = 4
4562
4563
4564class DFS_REFERRAL_ENTRY0(Packet):
4565 fields_desc = [
4566 StrNullFieldUtf16("DFSPath", ""),
4567 StrNullFieldUtf16("DFSAlternatePath", ""),
4568 StrNullFieldUtf16("NetworkAddress", ""),
4569 ]
4570
4571
4572class DFS_REFERRAL_ENTRY1(Packet):
4573 fields_desc = [
4574 StrNullFieldUtf16("SpecialName", ""),
4575 FieldListField(
4576 "ExpandedName",
4577 [],
4578 StrNullFieldUtf16("", ""),
4579 ),
4580 ]
4581
4582
4583class _DFS_Referrals_BufferField(PacketListField):
4584 def getfield(self, pkt, s):
4585 results = []
4586 offset = sum(x.Size for x in pkt.ReferralEntries)
4587 for ref in pkt.ReferralEntries:
4588 # For every ref
4589 if not ref.ReferralEntryFlags.NameListReferral:
4590 cls = DFS_REFERRAL_ENTRY0
4591 else:
4592 cls = DFS_REFERRAL_ENTRY1
4593 # Build the fields manually
4594 fld = _NTLMPayloadField(
4595 "",
4596 offset,
4597 cls.fields_desc,
4598 force_order=[x.name for x in cls.fields_desc],
4599 offset_name="Offset",
4600 )
4601 remain, vals = fld.getfield(ref, s)
4602 vals = fld.i2h(ref, vals)
4603 # Append the entry class
4604 results.append(cls(**{x[0]: x[1] for x in vals}))
4605 offset -= ref.Size
4606 return b"", results
4607
4608 def addfield(self, pkt, s, vals):
4609 offset = sum(len(x) for x in pkt.ReferralEntries)
4610 for i, val in enumerate(vals):
4611 try:
4612 ref = pkt.ReferralEntries[i]
4613 except KeyError:
4614 ref = None
4615 fld = _NTLMPayloadField(
4616 "",
4617 offset,
4618 val.fields_desc,
4619 force_order=[x.name for x in val.fields_desc],
4620 offset_name="Offset",
4621 )
4622 # Append the bytes manually
4623 values = [(fld.name, getattr(val, fld.name)) for fld in val.fields_desc]
4624 values = fld.h2i(ref, values)
4625 s += fld.addfield(ref, b"", values)
4626 offset -= len(ref)
4627 return s
4628
4629
4630class SMB2_IOCTL_RESP_GET_DFS_Referral(Packet):
4631 fields_desc = [
4632 LEShortField("PathConsumed", 0),
4633 FieldLenField("NumberOfReferrals", None, fmt="<H", count_of="ReferralEntries"),
4634 FlagsField(
4635 "ReferralHeaderFlags",
4636 0,
4637 -32,
4638 {
4639 0x00000001: "ReferralServers",
4640 0x00000002: "StorageServers",
4641 0x00000004: "TargetFailback",
4642 },
4643 ),
4644 PacketListField(
4645 "ReferralEntries",
4646 [],
4647 DFS_REFERRAL,
4648 count_from=lambda pkt: pkt.NumberOfReferrals,
4649 ),
4650 _DFS_Referrals_BufferField("ReferralBuffer", []),
4651 ]
4652
4653 def post_build(self, pkt, pay):
4654 # type: (bytes, bytes) -> bytes
4655 # Note: Windows is smart and uses some sort of compression in the sense
4656 # that it reuses fields that are used several times across ReferralBuffer.
4657 # But we just do the dumb thing because it's 'easier', and do no compression.
4658 offsets = {
4659 # DFS_REFERRAL_ENTRY0
4660 "DFSPath": 12,
4661 "DFSAlternatePath": 14,
4662 "NetworkAddress": 16,
4663 # DFS_REFERRAL_ENTRY1
4664 "SpecialName": 12,
4665 "ExpandedName": 16,
4666 }
4667 # dataoffset = pointer in the ReferralBuffer
4668 # entryoffset = pointer in the ReferralEntries
4669 dataoffset = sum(len(x) for x in self.ReferralEntries)
4670 entryoffset = 8
4671 for ref, buf in zip(self.ReferralEntries, self.ReferralBuffer):
4672 for fld in buf.fields_desc:
4673 off = entryoffset + offsets[fld.name]
4674 if ref.getfieldval(fld.name + "Offset") is None and buf.getfieldval(
4675 fld.name
4676 ):
4677 pkt = pkt[:off] + struct.pack("<H", dataoffset) + pkt[off + 2 :]
4678 dataoffset += len(fld.addfield(self, b"", buf.getfieldval(fld.name)))
4679 dataoffset -= len(ref)
4680 entryoffset += len(ref)
4681 return pkt + pay
4682
4683
4684# [MS-SMB2] various usages
4685
4686
4687def SMB2computePreauthIntegrityHashValue(
4688 PreauthIntegrityHashValue, s, HashId="SHA-512"
4689):
4690 """
4691 Update the PreauthIntegrityHashValue
4692 """
4693 # get hasher
4694 hasher = {"SHA-512": hashlib.sha512}[HashId]
4695 # compute the hash of concatenation of previous and bytes
4696 return hasher(PreauthIntegrityHashValue + s).digest()
4697
4698
4699# SMB2 socket and session
4700
4701
4702class SMBStreamSocket(StreamSocket):
4703 """
4704 A modified StreamSocket to dissect SMB compounded requests
4705 [MS-SMB2] 3.3.5.2.7
4706 """
4707
4708 def __init__(self, *args, **kwargs):
4709 self.queue = collections.deque()
4710 self.session = SMBSession()
4711 super(SMBStreamSocket, self).__init__(*args, **kwargs)
4712
4713 def recv(self, x=None):
4714 # note: normal StreamSocket takes care of NBTSession / DirectTCP fragments.
4715 # this takes care of splitting compounded requests
4716 if self.queue:
4717 pkt = self.queue.popleft()
4718 else:
4719 pkt = super(SMBStreamSocket, self).recv(x)
4720 # If there are multiple SMB2_Header requests (aka. compounded),
4721 # take the first and store the rest in a queue.
4722 if pkt is not None and (
4723 SMB2_Header in pkt
4724 or SMB2_Transform_Header in pkt
4725 or SMB2_Compression_Transform_Header in pkt
4726 ):
4727 pkt = self.session.in_pkt(pkt)
4728 pay = pkt[SMB2_Header].payload
4729 while SMB2_Header in pay:
4730 pay = pay[SMB2_Header]
4731 pay.underlayer.remove_payload()
4732 self.queue.append(pay)
4733 if not pay.NextCommand:
4734 break
4735 pay = pay.payload
4736 # Verify the signature if required.
4737 # This happens here because we must have split compounded requests first.
4738 smbh = pkt.getlayer(SMB2_Header)
4739 if (
4740 smbh
4741 and self.session.Dialect
4742 and self.session.SigningKey
4743 and self.session.SigningRequired
4744 # [MS-SMB2] sect 3.2.5.1.3 Verifying the Signature
4745 # "The client MUST skip the processing in this section if any of:"
4746 # - [...] decryption in section 3.2.5.1.1.1 succeeds
4747 and not smbh._decrypted
4748 # - MessageId is 0xFFFFFFFFFFFFFFFF
4749 and smbh.MID != 0xFFFFFFFFFFFFFFFF
4750 # - Status in the SMB2 header is STATUS_PENDING
4751 and smbh.Status != 0x00000103
4752 ):
4753 smbh.verify(
4754 self.session.Dialect,
4755 self.session.SigningKey,
4756 # SMB 3.1.1 parameters:
4757 SigningAlgorithmId=self.session.SigningAlgorithmId,
4758 IsClient=False,
4759 )
4760 return pkt
4761
4762 def send(self, x, Compounded=False, ForceSign=False, ForceEncrypt=False, **kwargs):
4763 for pkt in self.session.out_pkt(
4764 x, Compounded=Compounded, ForceSign=ForceSign, ForceEncrypt=ForceEncrypt
4765 ):
4766 return super(SMBStreamSocket, self).send(pkt, **kwargs)
4767
4768 @staticmethod
4769 def select(sockets, remain=conf.recv_poll_rate):
4770 if any(getattr(x, "queue", None) for x in sockets):
4771 return [x for x in sockets if isinstance(x, SMBStreamSocket) and x.queue]
4772 return select_objects(sockets, remain=remain)
4773
4774
4775class SMBSession(DefaultSession):
4776 """
4777 A SMB session within a TCP socket.
4778 """
4779
4780 def __init__(self, *args, **kwargs):
4781 self.smb_header = None
4782 self.ssp = kwargs.pop("ssp", None)
4783 self.sspcontext = kwargs.pop("sspcontext", None)
4784 self.sniffsspcontexts = {} # Unfinished contexts for passive
4785 # SMB session parameters
4786 self.CompoundQueue = []
4787 self.Dialect = 0x0202 # Updated by parent
4788 self.Credits = 0
4789 self.IsGuest = False
4790 self.MaxTransactionSize = 0
4791 self.MaxReadSize = 0
4792 self.MaxWriteSize = 0
4793 # Crypto parameters. Go read [MS-SMB2] to understand the names.
4794 self.SigningRequired = True
4795 self.SupportsEncryption = False
4796 self.EncryptData = False
4797 self.TreeEncryptData = False
4798 self.SigningKey = None
4799 self.EncryptionKey = None
4800 self.DecryptionKey = None
4801 self.PreauthIntegrityHashId = "SHA-512"
4802 self.SupportedCipherIds = [
4803 "AES-128-CCM",
4804 "AES-128-GCM",
4805 "AES-256-CCM",
4806 "AES-256-GCM",
4807 ]
4808 self.CipherId = "AES-128-CCM"
4809 self.SupportedSigningAlgorithmIds = [
4810 "AES-CMAC",
4811 "HMAC-SHA256",
4812 ]
4813 self.SigningAlgorithmId = None
4814 self.Salt = os.urandom(32)
4815 self.ConnectionPreauthIntegrityHashValue = None
4816 self.SessionPreauthIntegrityHashValue = None
4817 # SMB 3.1.1
4818 self.SessionPreauthIntegrityHashValue = None
4819 if conf.winssps_passive:
4820 for ssp in conf.winssps_passive:
4821 self.sniffsspcontexts[ssp] = None
4822 super(SMBSession, self).__init__(*args, **kwargs)
4823
4824 # SMB crypto functions
4825
4826 @crypto_validator
4827 def computeSMBSessionKeys(self, IsClient=None):
4828 """
4829 Compute the SigningKey and EncryptionKey (for SMB 3+)
4830 """
4831 if not getattr(self.sspcontext, "SessionKey", None):
4832 # no signing key, no session key
4833 return
4834 # [MS-SMB2] sect 3.3.5.5.3
4835 # SigningKey
4836 if self.Dialect >= 0x0300:
4837 if self.Dialect == 0x0311:
4838 label = b"SMBSigningKey\x00"
4839 context = self.SessionPreauthIntegrityHashValue
4840 else:
4841 label = b"SMB2AESCMAC\x00"
4842 context = b"SmbSign\x00"
4843 # [MS-SMB2] sect 3.1.4.2
4844 if "256" in self.CipherId:
4845 L = 256
4846 elif "128" in self.CipherId:
4847 L = 128
4848 else:
4849 raise ValueError
4850 self.SigningKey = SP800108_KDFCTR(
4851 self.sspcontext.SessionKey[:16],
4852 label,
4853 context,
4854 L,
4855 )
4856 # EncryptionKey / DecryptionKey
4857 if self.Dialect == 0x0311:
4858 if IsClient:
4859 label_out = b"SMBC2SCipherKey\x00"
4860 label_in = b"SMBS2CCipherKey\x00"
4861 else:
4862 label_out = b"SMBS2CCipherKey\x00"
4863 label_in = b"SMBC2SCipherKey\x00"
4864 context_out = context_in = self.SessionPreauthIntegrityHashValue
4865 else:
4866 label_out = label_in = b"SMB2AESCCM\x00"
4867 if IsClient:
4868 context_out = b"ServerIn \x00" # extra space per spec
4869 context_in = b"ServerOut\x00"
4870 else:
4871 context_out = b"ServerOut\x00"
4872 context_in = b"ServerIn \x00"
4873 self.EncryptionKey = SP800108_KDFCTR(
4874 self.sspcontext.SessionKey[: L // 8],
4875 label_out,
4876 context_out,
4877 L,
4878 )
4879 self.DecryptionKey = SP800108_KDFCTR(
4880 self.sspcontext.SessionKey[: L // 8],
4881 label_in,
4882 context_in,
4883 L,
4884 )
4885 elif self.Dialect <= 0x0210:
4886 self.SigningKey = self.sspcontext.SessionKey[:16]
4887 else:
4888 raise ValueError("Hmmm ? >:(")
4889
4890 def computeSMBConnectionPreauth(self, *negopkts):
4891 if self.Dialect and self.Dialect >= 0x0311: # SMB 3.1.1 only
4892 # [MS-SMB2] 3.3.5.4
4893 # TODO: handle SMB2_SESSION_FLAG_BINDING
4894 if self.ConnectionPreauthIntegrityHashValue is None:
4895 # New auth or failure
4896 self.ConnectionPreauthIntegrityHashValue = b"\x00" * 64
4897 # Calculate the *Connection* PreauthIntegrityHashValue
4898 for negopkt in negopkts:
4899 self.ConnectionPreauthIntegrityHashValue = (
4900 SMB2computePreauthIntegrityHashValue(
4901 self.ConnectionPreauthIntegrityHashValue,
4902 negopkt,
4903 HashId=self.PreauthIntegrityHashId,
4904 )
4905 )
4906
4907 def computeSMBSessionPreauth(self, *sesspkts):
4908 if self.Dialect and self.Dialect >= 0x0311: # SMB 3.1.1 only
4909 # [MS-SMB2] 3.3.5.5.3
4910 if self.SessionPreauthIntegrityHashValue is None:
4911 # New auth or failure
4912 self.SessionPreauthIntegrityHashValue = (
4913 self.ConnectionPreauthIntegrityHashValue
4914 )
4915 # Calculate the *Session* PreauthIntegrityHashValue
4916 for sesspkt in sesspkts:
4917 self.SessionPreauthIntegrityHashValue = (
4918 SMB2computePreauthIntegrityHashValue(
4919 self.SessionPreauthIntegrityHashValue,
4920 sesspkt,
4921 HashId=self.PreauthIntegrityHashId,
4922 )
4923 )
4924
4925 # I/O
4926
4927 def in_pkt(self, pkt):
4928 """
4929 Incoming SMB packet
4930 """
4931 if SMB2_Transform_Header in pkt:
4932 # Packet is encrypted
4933 pkt = pkt[SMB2_Transform_Header].decrypt(
4934 self.Dialect,
4935 self.DecryptionKey,
4936 CipherId=self.CipherId,
4937 )
4938 # Signature is verified in SMBStreamSocket
4939 return pkt
4940
4941 def out_pkt(self, pkt, Compounded=False, ForceSign=False, ForceEncrypt=False):
4942 """
4943 Outgoing SMB packet
4944
4945 :param pkt: the packet to send
4946 :param Compound: if True, will be stack to be send with the next
4947 un-compounded packet
4948 :param ForceSign: if True, force to sign the packet.
4949 :param ForceEncrypt: if True, force to encrypt the packet.
4950
4951 Handles:
4952 - handle compounded requests (if any): [MS-SMB2] 3.3.5.2.7
4953 - handles signing and encryption (if required)
4954 """
4955 # Note: impacket and wireshark get crazy on compounded+signature, but
4956 # windows+samba tells we're right :D
4957 if SMB2_Header in pkt:
4958 if self.CompoundQueue:
4959 # this is a subsequent compound: only keep the SMB2
4960 pkt = pkt[SMB2_Header]
4961 if Compounded:
4962 # [MS-SMB2] 3.2.4.1.4
4963 # "Compounded requests MUST be aligned on 8-byte boundaries; the
4964 # last request of the compounded requests does not need to be padded to
4965 # an 8-byte boundary."
4966 # [MS-SMB2] 3.1.4.1
4967 # "If the message is part of a compounded chain, any
4968 # padding at the end of the message MUST be used in the hash
4969 # computation."
4970 length = len(pkt[SMB2_Header])
4971 padlen = (-length) % 8
4972 if padlen:
4973 pkt.add_payload(b"\x00" * padlen)
4974 pkt[SMB2_Header].NextCommand = length + padlen
4975 if (
4976 self.Dialect
4977 and self.SigningKey
4978 and (ForceSign or self.SigningRequired and not ForceEncrypt)
4979 ):
4980 # [MS-SMB2] sect 3.2.4.1.1 - Signing
4981 smb = pkt[SMB2_Header]
4982 smb.Flags += "SMB2_FLAGS_SIGNED"
4983 smb.sign(
4984 self.Dialect,
4985 self.SigningKey,
4986 # SMB 3.1.1 parameters:
4987 SigningAlgorithmId=self.SigningAlgorithmId,
4988 IsClient=False,
4989 )
4990 if Compounded:
4991 # There IS a next compound. Store in queue
4992 self.CompoundQueue.append(pkt)
4993 return []
4994 else:
4995 # If there are any compounded responses in store, sum them
4996 if self.CompoundQueue:
4997 pkt = functools.reduce(lambda x, y: x / y, self.CompoundQueue) / pkt
4998 self.CompoundQueue.clear()
4999 if self.EncryptionKey and (
5000 ForceEncrypt or self.EncryptData or self.TreeEncryptData
5001 ):
5002 # [MS-SMB2] sect 3.1.4.3 - Encrypting the message
5003 smb = pkt[SMB2_Header]
5004 assert not smb.Flags.SMB2_FLAGS_SIGNED
5005 smbt = smb.encrypt(
5006 self.Dialect,
5007 self.EncryptionKey,
5008 CipherId=self.CipherId,
5009 )
5010 if smb.underlayer:
5011 # If there's an underlayer, replace current SMB header
5012 smb.underlayer.payload = smbt
5013 else:
5014 smb = smbt
5015 return [pkt]
5016
5017 def process(self, pkt: Packet):
5018 # Called when passively sniffing
5019 pkt = super(SMBSession, self).process(pkt)
5020 if pkt is not None and SMB2_Header in pkt:
5021 return self.in_pkt(pkt)
5022 return pkt