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