Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scapy/layers/smb.py: 72%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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) Philippe Biondi <phil@secdev.org>
5# Copyright (C) Gabriel Potter
7"""
8SMB 1.0 (Server Message Block), also known as CIFS.
10.. note::
11 You will find more complete documentation for this layer over at
12 `SMB <https://scapy.readthedocs.io/en/latest/layers/smb.html>`_
14Specs:
16- [MS-CIFS] (base)
17- [MS-SMB] (extension of CIFS - SMB v1)
18"""
20import struct
22from scapy.config import conf
23from scapy.packet import Packet, bind_layers, bind_top_down
24from scapy.fields import (
25 ByteEnumField,
26 ByteField,
27 ConditionalField,
28 FieldLenField,
29 FieldListField,
30 FlagsField,
31 IPField,
32 LEFieldLenField,
33 LEIntEnumField,
34 LEIntField,
35 LELongField,
36 LEShortEnumField,
37 LEShortField,
38 MultipleTypeField,
39 PacketField,
40 PacketLenField,
41 PacketListField,
42 ReversePadField,
43 ScalingField,
44 ShortField,
45 StrFixedLenField,
46 StrNullField,
47 StrNullFieldUtf16,
48 UTCTimeField,
49 UUIDField,
50 XLEShortField,
51 XStrLenField,
52)
54from scapy.layers.dns import (
55 DNSStrField,
56 DNSCompressedPacket,
57)
58from scapy.layers.ntlm import (
59 _NTLMPayloadPacket,
60 _NTLMPayloadField,
61 _NTLM_ENUM,
62 _NTLM_post_build,
63)
64from scapy.layers.netbios import NBTSession, NBTDatagram
65from scapy.layers.gssapi import (
66 GSSAPI_BLOB,
67)
68from scapy.layers.smb2 import (
69 STATUS_ERREF,
70 SMB2_Header,
71)
74SMB_COM = {
75 0x00: "SMB_COM_CREATE_DIRECTORY",
76 0x01: "SMB_COM_DELETE_DIRECTORY",
77 0x02: "SMB_COM_OPEN",
78 0x03: "SMB_COM_CREATE",
79 0x04: "SMB_COM_CLOSE",
80 0x05: "SMB_COM_FLUSH",
81 0x06: "SMB_COM_DELETE",
82 0x07: "SMB_COM_RENAME",
83 0x08: "SMB_COM_QUERY_INFORMATION",
84 0x09: "SMB_COM_SET_INFORMATION",
85 0x0A: "SMB_COM_READ",
86 0x0B: "SMB_COM_WRITE",
87 0x0C: "SMB_COM_LOCK_BYTE_RANGE",
88 0x0D: "SMB_COM_UNLOCK_BYTE_RANGE",
89 0x0E: "SMB_COM_CREATE_TEMPORARY",
90 0x0F: "SMB_COM_CREATE_NEW",
91 0x10: "SMB_COM_CHECK_DIRECTORY",
92 0x11: "SMB_COM_PROCESS_EXIT",
93 0x12: "SMB_COM_SEEK",
94 0x13: "SMB_COM_LOCK_AND_READ",
95 0x14: "SMB_COM_WRITE_AND_UNLOCK",
96 0x1A: "SMB_COM_READ_RAW",
97 0x1B: "SMB_COM_READ_MPX",
98 0x1C: "SMB_COM_READ_MPX_SECONDARY",
99 0x1D: "SMB_COM_WRITE_RAW",
100 0x1E: "SMB_COM_WRITE_MPX",
101 0x1F: "SMB_COM_WRITE_MPX_SECONDARY",
102 0x20: "SMB_COM_WRITE_COMPLETE",
103 0x21: "SMB_COM_QUERY_SERVER",
104 0x22: "SMB_COM_SET_INFORMATION2",
105 0x23: "SMB_COM_QUERY_INFORMATION2",
106 0x24: "SMB_COM_LOCKING_ANDX",
107 0x25: "SMB_COM_TRANSACTION",
108 0x26: "SMB_COM_TRANSACTION_SECONDARY",
109 0x27: "SMB_COM_IOCTL",
110 0x28: "SMB_COM_IOCTL_SECONDARY",
111 0x29: "SMB_COM_COPY",
112 0x2A: "SMB_COM_MOVE",
113 0x2B: "SMB_COM_ECHO",
114 0x2C: "SMB_COM_WRITE_AND_CLOSE",
115 0x2D: "SMB_COM_OPEN_ANDX",
116 0x2E: "SMB_COM_READ_ANDX",
117 0x2F: "SMB_COM_WRITE_ANDX",
118 0x30: "SMB_COM_NEW_FILE_SIZE",
119 0x31: "SMB_COM_CLOSE_AND_TREE_DISC",
120 0x32: "SMB_COM_TRANSACTION2",
121 0x33: "SMB_COM_TRANSACTION2_SECONDARY",
122 0x34: "SMB_COM_FIND_CLOSE2",
123 0x35: "SMB_COM_FIND_NOTIFY_CLOSE",
124 0x70: "SMB_COM_TREE_CONNECT",
125 0x71: "SMB_COM_TREE_DISCONNECT",
126 0x72: "SMB_COM_NEGOTIATE",
127 0x73: "SMB_COM_SESSION_SETUP_ANDX",
128 0x74: "SMB_COM_LOGOFF_ANDX",
129 0x75: "SMB_COM_TREE_CONNECT_ANDX",
130 0x7E: "SMB_COM_SECURITY_PACKAGE_ANDX",
131 0x80: "SMB_COM_QUERY_INFORMATION_DISK",
132 0x81: "SMB_COM_SEARCH",
133 0x82: "SMB_COM_FIND",
134 0x83: "SMB_COM_FIND_UNIQUE",
135 0x84: "SMB_COM_FIND_CLOSE",
136 0xA0: "SMB_COM_NT_TRANSACT",
137 0xA1: "SMB_COM_NT_TRANSACT_SECONDARY",
138 0xA2: "SMB_COM_NT_CREATE_ANDX",
139 0xA4: "SMB_COM_NT_CANCEL",
140 0xA5: "SMB_COM_NT_RENAME",
141 0xC0: "SMB_COM_OPEN_PRINT_FILE",
142 0xC1: "SMB_COM_WRITE_PRINT_FILE",
143 0xC2: "SMB_COM_CLOSE_PRINT_FILE",
144 0xC3: "SMB_COM_GET_PRINT_QUEUE",
145 0xD8: "SMB_COM_READ_BULK",
146 0xD9: "SMB_COM_WRITE_BULK",
147 0xDA: "SMB_COM_WRITE_BULK_DATA",
148 0xFE: "SMB_COM_INVALID",
149 0xFF: "SMB_COM_NO_ANDX_COMMAND",
150}
153class SMB_Header(Packet):
154 name = "SMB 1 Protocol Request Header"
155 fields_desc = [
156 StrFixedLenField("Start", b"\xffSMB", 4),
157 ByteEnumField("Command", 0x72, SMB_COM),
158 LEIntEnumField("Status", 0, STATUS_ERREF),
159 FlagsField(
160 "Flags",
161 0x18,
162 8,
163 [
164 "LOCK_AND_READ_OK",
165 "BUF_AVAIL",
166 "res",
167 "CASE_INSENSITIVE",
168 "CANONICALIZED_PATHS",
169 "OPLOCK",
170 "OPBATCH",
171 "REPLY",
172 ],
173 ),
174 FlagsField(
175 "Flags2",
176 0x0000,
177 -16,
178 [
179 "LONG_NAMES",
180 "EAS",
181 "SMB_SECURITY_SIGNATURE",
182 "COMPRESSED",
183 "SMB_SECURITY_SIGNATURE_REQUIRED",
184 "res",
185 "IS_LONG_NAME",
186 "res",
187 "res",
188 "res",
189 "REPARSE_PATH",
190 "EXTENDED_SECURITY",
191 "DFS",
192 "PAGING_IO",
193 "NT_STATUS",
194 "UNICODE",
195 ],
196 ),
197 LEShortField("PIDHigh", 0x0000),
198 StrFixedLenField("SecuritySignature", b"", length=8),
199 LEShortField("Reserved", 0x0),
200 LEShortField("TID", 0),
201 LEShortField("PIDLow", 0),
202 LEShortField("UID", 0),
203 LEShortField("MID", 0),
204 ]
206 def guess_payload_class(self, payload):
207 # type: (bytes) -> Packet
208 if not payload:
209 return super(SMB_Header, self).guess_payload_class(payload)
210 WordCount = ord(payload[:1])
211 if self.Command == 0x72:
212 if self.Flags.REPLY:
213 if self.Flags2.EXTENDED_SECURITY:
214 return SMBNegotiate_Response_Extended_Security
215 else:
216 return SMBNegotiate_Response_Security
217 else:
218 return SMBNegotiate_Request
219 elif self.Command == 0x73:
220 if WordCount == 0:
221 return SMBSession_Null
222 if self.Flags.REPLY:
223 if WordCount == 0x04:
224 return SMBSession_Setup_AndX_Response_Extended_Security
225 elif WordCount == 0x03:
226 return SMBSession_Setup_AndX_Response
227 if self.Flags2.EXTENDED_SECURITY:
228 return SMBSession_Setup_AndX_Response_Extended_Security
229 else:
230 return SMBSession_Setup_AndX_Response
231 else:
232 if WordCount == 0x0C:
233 return SMBSession_Setup_AndX_Request_Extended_Security
234 elif WordCount == 0x0D:
235 return SMBSession_Setup_AndX_Request
236 if self.Flags2.EXTENDED_SECURITY:
237 return SMBSession_Setup_AndX_Request_Extended_Security
238 else:
239 return SMBSession_Setup_AndX_Request
240 elif self.Command == 0x25:
241 if self.Flags.REPLY:
242 if WordCount == 0x11:
243 return SMBMailslot_Write
244 else:
245 return SMBTransaction_Response
246 else:
247 if WordCount == 0x11:
248 return SMBMailslot_Write
249 else:
250 return SMBTransaction_Request
251 return super(SMB_Header, self).guess_payload_class(payload)
253 def answers(self, pkt):
254 return SMB_Header in pkt
257# SMB Negotiate Request
260class SMB_Dialect(Packet):
261 name = "SMB Dialect"
262 fields_desc = [
263 ByteField("BufferFormat", 0x02),
264 StrNullField("DialectString", "NT LM 0.12"),
265 ]
267 def default_payload_class(self, payload):
268 return conf.padding_layer
271class SMBNegotiate_Request(Packet):
272 name = "SMB Negotiate Request"
273 fields_desc = [
274 ByteField("WordCount", 0),
275 LEFieldLenField("ByteCount", None, length_of="Dialects"),
276 PacketListField(
277 "Dialects",
278 [SMB_Dialect()],
279 SMB_Dialect,
280 length_from=lambda pkt: pkt.ByteCount,
281 ),
282 ]
285bind_layers(SMB_Header, SMBNegotiate_Request, Command=0x72)
287# SMBNegociate Protocol Response
290def _SMBStrNullField(name, default):
291 """
292 Returns a StrNullField that is either normal or UTF-16 depending
293 on the SMB headers.
294 """
296 def _isUTF16(pkt):
297 while not hasattr(pkt, "Flags2") and pkt.underlayer:
298 pkt = pkt.underlayer
299 return hasattr(pkt, "Flags2") and pkt.Flags2.UNICODE
301 return MultipleTypeField(
302 [(StrNullFieldUtf16(name, default), _isUTF16)],
303 StrNullField(name, default),
304 )
307def _len(pkt, name):
308 """
309 Returns the length of a field, works with Unicode strings.
310 """
311 fld, v = pkt.getfield_and_val(name)
312 return len(fld.addfield(pkt, v, b""))
315class _SMBNegotiate_Response(Packet):
316 @classmethod
317 def dispatch_hook(cls, _pkt=None, *args, **kargs):
318 if _pkt and len(_pkt) >= 2:
319 # Yes this is inspired by
320 # https://github.com/wireshark/wireshark/blob/925e01b23fd5aad2fa929fafd894128a88832e74/epan/dissectors/packet-smb.c#L2902
321 wc = struct.unpack("<H", _pkt[:1])
322 # dialect = struct.unpack("<H", _pkt[1:3])
323 if wc == 1:
324 # Core Protocol
325 return SMBNegotiate_Response_NoSecurity
326 elif wc == 0xD:
327 # LAN Manager 1.0 - LAN Manager 2.1
328 # TODO
329 pass
330 elif wc == 0x11:
331 # NT LAN Manager
332 return cls
333 return cls
336_SMB_ServerCapabilities = [
337 "RAW_MODE",
338 "MPX_MODE",
339 "UNICODE",
340 "LARGE_FILES",
341 "NT_SMBS",
342 "RPC_REMOTE_APIS",
343 "STATUS32",
344 "LEVEL_II_OPLOCKS",
345 "LOCK_AND_READ",
346 "NT_FIND",
347 "res",
348 "res",
349 "DFS",
350 "INFOLEVEL_PASSTHRU",
351 "LARGE_READX",
352 "LARGE_WRITEX",
353 "LWIO",
354 "res",
355 "res",
356 "res",
357 "res",
358 "res",
359 "res",
360 "UNIX",
361 "res",
362 "COMPRESSED_DATA",
363 "res",
364 "res",
365 "res",
366 "DYNAMIC_REAUTH",
367 "PERSISTENT_HANDLES",
368 "EXTENDED_SECURITY",
369]
372# CIFS sect 2.2.4.52.2
375class SMBNegotiate_Response_NoSecurity(_SMBNegotiate_Response):
376 name = "SMB Negotiate No-Security Response (CIFS)"
377 fields_desc = [
378 ByteField("WordCount", 0x1),
379 LEShortField("DialectIndex", 7),
380 FlagsField(
381 "SecurityMode",
382 0x03,
383 8,
384 [
385 "USER_SECURITY",
386 "ENCRYPT_PASSWORDS",
387 "SECURITY_SIGNATURES_ENABLED",
388 "SECURITY_SIGNATURES_REQUIRED",
389 ],
390 ),
391 LEShortField("MaxMpxCount", 50),
392 LEShortField("MaxNumberVC", 1),
393 LEIntField("MaxBufferSize", 16144), # Windows: 4356
394 LEIntField("MaxRawSize", 65536),
395 LEIntField("SessionKey", 0x0000),
396 FlagsField("ServerCapabilities", 0xF3F9, -32, _SMB_ServerCapabilities),
397 UTCTimeField(
398 "ServerTime",
399 None,
400 fmt="<Q",
401 epoch=[1601, 1, 1, 0, 0, 0],
402 custom_scaling=1e7,
403 ),
404 ScalingField("ServerTimeZone", 0x3C, fmt="<h", unit="min-UTC"),
405 FieldLenField(
406 "ChallengeLength",
407 None,
408 # aka EncryptionKeyLength
409 length_of="Challenge",
410 fmt="<B",
411 ),
412 LEFieldLenField(
413 "ByteCount",
414 None,
415 length_of="DomainName",
416 adjust=lambda pkt, x: x + len(pkt.Challenge),
417 ),
418 XStrLenField(
419 "Challenge",
420 b"", # aka EncryptionKey
421 length_from=lambda pkt: pkt.ChallengeLength,
422 ),
423 StrNullField("DomainName", "WORKGROUP"),
424 ]
427bind_top_down(SMB_Header, SMBNegotiate_Response_NoSecurity, Command=0x72, Flags=0x80)
429# SMB sect 2.2.4.5.2.1
432class SMBNegotiate_Response_Extended_Security(_SMBNegotiate_Response):
433 name = "SMB Negotiate Extended Security Response (SMB)"
434 WordCount = 0x11
435 fields_desc = SMBNegotiate_Response_NoSecurity.fields_desc[:12] + [
436 LEFieldLenField(
437 "ByteCount", None, length_of="SecurityBlob", adjust=lambda _, x: x + 16
438 ),
439 SMBNegotiate_Response_NoSecurity.fields_desc[13],
440 UUIDField("GUID", None, uuid_fmt=UUIDField.FORMAT_LE),
441 PacketLenField(
442 "SecurityBlob", None, GSSAPI_BLOB, length_from=lambda x: x.ByteCount - 16
443 ),
444 ]
447bind_top_down(
448 SMB_Header,
449 SMBNegotiate_Response_Extended_Security,
450 Command=0x72,
451 Flags=0x80,
452 Flags2=0x800,
453)
455# SMB sect 2.2.4.5.2.2
458class SMBNegotiate_Response_Security(_SMBNegotiate_Response):
459 name = "SMB Negotiate Non-Extended Security Response (SMB)"
460 WordCount = 0x11
461 fields_desc = SMBNegotiate_Response_NoSecurity.fields_desc[:12] + [
462 LEFieldLenField(
463 "ByteCount",
464 None,
465 length_of="DomainName",
466 adjust=lambda pkt, x: x
467 + 2
468 + _len(pkt, "Challenge")
469 + _len(pkt, "ServerName"),
470 ),
471 XStrLenField(
472 "Challenge",
473 b"", # aka EncryptionKey
474 length_from=lambda pkt: pkt.ChallengeLength,
475 ),
476 _SMBStrNullField("DomainName", "WORKGROUP"),
477 _SMBStrNullField("ServerName", "RMFF1"),
478 ]
481bind_top_down(SMB_Header, SMBNegotiate_Response_Security, Command=0x72, Flags=0x80)
483# Session Setup AndX Request
485# CIFS sect 2.2.4.53
488class SMBSession_Setup_AndX_Request(Packet):
489 name = "Session Setup AndX Request (CIFS)"
490 fields_desc = [
491 ByteField("WordCount", 0x0D),
492 ByteEnumField("AndXCommand", 0xFF, SMB_COM),
493 ByteField("AndXReserved", 0),
494 LEShortField("AndXOffset", None),
495 LEShortField("MaxBufferSize", 16144), # Windows: 4356
496 LEShortField("MaxMPXCount", 50),
497 LEShortField("VCNumber", 0),
498 LEIntField("SessionKey", 0),
499 LEFieldLenField("OEMPasswordLength", None, length_of="OEMPassword"),
500 LEFieldLenField("UnicodePasswordLength", None, length_of="UnicodePassword"),
501 LEIntField("Reserved", 0),
502 FlagsField("ServerCapabilities", 0x05, -32, _SMB_ServerCapabilities),
503 LEShortField("ByteCount", None),
504 XStrLenField("OEMPassword", "Pass", length_from=lambda x: x.OEMPasswordLength),
505 XStrLenField(
506 "UnicodePassword", "Pass", length_from=lambda x: x.UnicodePasswordLength
507 ),
508 ReversePadField(_SMBStrNullField("AccountName", "GUEST"), 2, b"\0"),
509 _SMBStrNullField("PrimaryDomain", ""),
510 _SMBStrNullField("NativeOS", "Windows 4.0"),
511 _SMBStrNullField("NativeLanMan", "Windows 4.0"),
512 ]
514 def post_build(self, pkt, pay):
515 if self.AndXOffset is None and self.AndXCommand != 0xFF:
516 pkt = pkt[:3] + struct.pack("<H", len(pkt) + 32) + pkt[5:]
517 if self.ByteCount is None:
518 pkt = pkt[:27] + struct.pack("<H", len(pkt) - 29) + pkt[29:]
519 if self.payload and hasattr(self.payload, "AndXOffset") and pay:
520 pay = pay[:3] + struct.pack("<H", len(pkt) + len(pay) + 32) + pay[5:]
521 return pkt + pay
524bind_top_down(SMB_Header, SMBSession_Setup_AndX_Request, Command=0x73)
526# SMB sect 2.2.4.7
529class SMBTree_Connect_AndX(Packet):
530 name = "Session Tree Connect AndX"
531 WordCount = 0x04
532 fields_desc = SMBSession_Setup_AndX_Request.fields_desc[:4] + [
533 FlagsField(
534 "Flags",
535 "",
536 -16,
537 ["DISCONNECT_TID", "r2", "EXTENDED_SIGNATURES", "EXTENDED_RESPONSE"],
538 ),
539 FieldLenField("PasswordLength", None, length_of="Password", fmt="<H"),
540 LEShortField("ByteCount", None),
541 XStrLenField("Password", b"", length_from=lambda pkt: pkt.PasswordLength),
542 ReversePadField(_SMBStrNullField("Path", "\\\\WIN2K\\IPC$"), 2),
543 StrNullField("Service", "?????"),
544 ]
546 def post_build(self, pkt, pay):
547 pkt += pay
548 if self.ByteCount is None:
549 pkt = pkt[:9] + struct.pack("<H", len(pkt) - 11) + pkt[11:]
550 return pkt
553bind_layers(SMB_Header, SMBTree_Connect_AndX, Command=0x75)
554bind_layers(SMBSession_Setup_AndX_Request, SMBTree_Connect_AndX, AndXCommand=0x75)
556# SMB sect 2.2.4.6.1
559class SMBSession_Setup_AndX_Request_Extended_Security(Packet):
560 name = "Session Setup AndX Extended Security Request (SMB)"
561 WordCount = 0x0C
562 fields_desc = (
563 SMBSession_Setup_AndX_Request.fields_desc[:8]
564 + [
565 LEFieldLenField("SecurityBlobLength", None, length_of="SecurityBlob"),
566 ]
567 + SMBSession_Setup_AndX_Request.fields_desc[10:12]
568 + [
569 LEShortField("ByteCount", None),
570 PacketLenField(
571 "SecurityBlob",
572 None,
573 GSSAPI_BLOB,
574 length_from=lambda x: x.SecurityBlobLength,
575 ),
576 ReversePadField(
577 _SMBStrNullField("NativeOS", "Windows 4.0"),
578 2,
579 b"\0",
580 ),
581 _SMBStrNullField("NativeLanMan", "Windows 4.0"),
582 ]
583 )
585 def post_build(self, pkt, pay):
586 if self.ByteCount is None:
587 pkt = pkt[:25] + struct.pack("<H", len(pkt) - 27) + pkt[27:]
588 return pkt + pay
591bind_top_down(
592 SMB_Header,
593 SMBSession_Setup_AndX_Request_Extended_Security,
594 Command=0x73,
595 Flags2=0x800,
596)
598# Session Setup AndX Response
601# CIFS sect 2.2.4.53.2
604class SMBSession_Setup_AndX_Response(Packet):
605 name = "Session Setup AndX Response (CIFS)"
606 fields_desc = [
607 ByteField("WordCount", 0x3),
608 ByteEnumField("AndXCommand", 0xFF, SMB_COM),
609 ByteField("AndXReserved", 0),
610 LEShortField("AndXOffset", None),
611 FlagsField(
612 "Action",
613 0,
614 -16,
615 {
616 0x0001: "SMB_SETUP_GUEST",
617 0x0002: "SMB_SETUP_USE_LANMAN_KEY",
618 },
619 ),
620 LEShortField("ByteCount", 25),
621 _SMBStrNullField("NativeOS", "Windows 4.0"),
622 _SMBStrNullField("NativeLanMan", "Windows 4.0"),
623 _SMBStrNullField("PrimaryDomain", ""),
624 # Off spec?
625 ByteField("WordCount2", 3),
626 ByteEnumField("AndXCommand2", 0xFF, SMB_COM),
627 ByteField("Reserved3", 0),
628 LEShortField("AndXOffset2", 80),
629 LEShortField("OptionalSupport", 0x01),
630 LEShortField("ByteCount2", 5),
631 StrNullField("Service", "IPC"),
632 StrNullField("NativeFileSystem", ""),
633 ]
635 def post_build(self, pkt, pay):
636 if self.AndXOffset is None:
637 pkt = pkt[:3] + struct.pack("<H", len(pkt) + 32) + pkt[5:]
638 return pkt + pay
641bind_top_down(SMB_Header, SMBSession_Setup_AndX_Response, Command=0x73, Flags=0x80)
643# SMB sect 2.2.4.6.2
646class SMBSession_Setup_AndX_Response_Extended_Security(
647 SMBSession_Setup_AndX_Response
648): # noqa: E501
649 name = "Session Setup AndX Extended Security Response (SMB)"
650 WordCount = 0x4
651 fields_desc = (
652 SMBSession_Setup_AndX_Response.fields_desc[:5]
653 + [SMBSession_Setup_AndX_Request_Extended_Security.fields_desc[8]]
654 + SMBSession_Setup_AndX_Request_Extended_Security.fields_desc[11:]
655 )
657 def post_build(self, pkt, pay):
658 if self.ByteCount is None:
659 pkt = pkt[:9] + struct.pack("<H", len(pkt) - 11) + pkt[11:]
660 return super(SMBSession_Setup_AndX_Response_Extended_Security, self).post_build(
661 pkt, pay
662 )
665bind_top_down(
666 SMB_Header,
667 SMBSession_Setup_AndX_Response_Extended_Security,
668 Command=0x73,
669 Flags=0x80,
670 Flags2=0x800,
671)
673# SMB null (no wordcount)
676class SMBSession_Null(Packet):
677 fields_desc = [ByteField("WordCount", 0), LEShortField("ByteCount", 0)]
680bind_top_down(SMB_Header, SMBSession_Null, Command=0x73)
682# [MS-CIFS] sect 2.2.4.33.1
684_SMB_CONFIG = [
685 ("Len", _NTLM_ENUM.LEN),
686 ("BufferOffset", _NTLM_ENUM.OFFSET),
687]
690class _SMB_TransactionRequest_Data(PacketLenField):
691 def m2i(self, pkt, m):
692 if pkt.Name == b"\\MAILSLOT\\NET\\NETLOGON":
693 return NETLOGON(m)
694 elif pkt.Name == b"\\MAILSLOT\\BROWSE" or pkt.name == b"\\MAILSLOT\\LANMAN":
695 return BRWS(m)
696 return conf.raw_layer(m)
699def _optlen(pkt, x):
700 try:
701 return len(getattr(pkt, x))
702 except AttributeError:
703 return 0
706class SMBTransaction_Request(_NTLMPayloadPacket):
707 name = "SMB COM Transaction Request"
708 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
710 fields_desc = [
711 FieldLenField(
712 "WordCount",
713 None,
714 length_of="SetupCount",
715 adjust=lambda pkt, x: x + 0x0E,
716 fmt="B",
717 ),
718 FieldLenField(
719 "TotalParamCount",
720 None,
721 length_of="Buffer",
722 fmt="<H",
723 adjust=lambda pkt, _: _optlen(pkt, "Parameter"),
724 ),
725 FieldLenField(
726 "TotalDataCount",
727 None,
728 length_of="Buffer",
729 fmt="<H",
730 adjust=lambda pkt, _: _optlen(pkt, "Data"),
731 ),
732 LEShortField("MaxParamCount", 0),
733 LEShortField("MaxDataCount", 0),
734 ByteField("MaxSetupCount", 0),
735 ByteField("Reserved1", 0),
736 FlagsField("Flags", 0, -16, {0x1: "DISCONNECT_TID", 0x2: "NO_RESPONSE"}),
737 LEIntField("Timeout", 1000),
738 ShortField("Reserved2", 0),
739 LEShortField("ParameterLen", None),
740 LEShortField("ParameterBufferOffset", None),
741 LEShortField("DataLen", None),
742 LEShortField("DataBufferOffset", None),
743 FieldLenField("SetupCount", 3, count_of="Setup", fmt="B"),
744 ByteField("Reserved3", 0),
745 FieldListField(
746 "Setup",
747 [1, 1, 2],
748 LEShortField("", 0),
749 count_from=lambda pkt: pkt.SetupCount,
750 ),
751 # SMB Data
752 FieldLenField(
753 "ByteCount",
754 None,
755 length_of="Name",
756 fmt="<H",
757 adjust=lambda pkt, x: x + _optlen(pkt, "Parameter") + _optlen(pkt, "Data"),
758 ),
759 StrNullField("Name", "\\MAILSLOT\\NET\\NETLOGON"),
760 _NTLMPayloadField(
761 "Buffer",
762 lambda pkt: 32 + 31 + len(pkt.Setup) * 2 + len(pkt.Name) + 1,
763 [
764 XStrLenField(
765 "Parameter", b"", length_from=lambda pkt: pkt.ParameterLen
766 ),
767 _SMB_TransactionRequest_Data(
768 "Data", None, conf.raw_layer, length_from=lambda pkt: pkt.DataLen
769 ),
770 ],
771 ),
772 ]
774 def post_build(self, pkt, pay):
775 # type: (bytes, bytes) -> bytes
776 return (
777 _NTLM_post_build(
778 self,
779 pkt,
780 32 + 31 + len(self.Setup) * 2 + len(self.Name) + 1,
781 {
782 "Parameter": 19,
783 "Data": 23,
784 },
785 config=_SMB_CONFIG,
786 )
787 + pay
788 )
790 def mysummary(self):
791 if self.DataLen:
792 return self.sprintf("Tran %Name% ") + self.Data.mysummary()
793 return self.sprintf("Tran %Name%")
796bind_top_down(SMB_Header, SMBTransaction_Request, Command=0x25)
799class SMBMailslot_Write(SMBTransaction_Request):
800 WordCount = 0x11
803# [MS-CIFS] sect 2.2.4.33.2
806class SMBTransaction_Response(_NTLMPayloadPacket):
807 name = "SMB COM Transaction Response"
808 _NTLM_PAYLOAD_FIELD_NAME = "Buffer"
809 fields_desc = [
810 FieldLenField(
811 "WordCount",
812 None,
813 length_of="SetupCount",
814 adjust=lambda pkt, x: x + 0x0A,
815 fmt="B",
816 ),
817 FieldLenField(
818 "TotalParamCount",
819 None,
820 length_of="Buffer",
821 fmt="<H",
822 adjust=lambda pkt, _: _optlen(pkt, "Parameter"),
823 ),
824 FieldLenField(
825 "TotalDataCount",
826 None,
827 length_of="Buffer",
828 fmt="<H",
829 adjust=lambda pkt, _: _optlen(pkt, "Data"),
830 ),
831 LEShortField("Reserved1", None),
832 LEShortField("ParameterLen", None),
833 LEShortField("ParameterBufferOffset", None),
834 LEShortField("ParameterDisplacement", 0),
835 LEShortField("DataLen", None),
836 LEShortField("DataBufferOffset", None),
837 LEShortField("DataDisplacement", 0),
838 FieldLenField("SetupCount", 3, count_of="Setup", fmt="B"),
839 ByteField("Reserved2", 0),
840 FieldListField(
841 "Setup",
842 [1, 1, 2],
843 LEShortField("", 0),
844 count_from=lambda pkt: pkt.SetupCount,
845 ),
846 # SMB Data
847 FieldLenField(
848 "ByteCount",
849 None,
850 length_of="Buffer",
851 fmt="<H",
852 adjust=lambda pkt, x: _optlen(pkt, "Parameter") + _optlen(pkt, "Data"),
853 ),
854 _NTLMPayloadField(
855 "Buffer",
856 lambda pkt: 32 + 22 + len(pkt.Setup) * 2,
857 [
858 XStrLenField(
859 "Parameter", b"", length_from=lambda pkt: pkt.ParameterLen
860 ),
861 XStrLenField("Data", b"", length_from=lambda pkt: pkt.DataLen),
862 ],
863 ),
864 ]
866 def post_build(self, pkt, pay):
867 # type: (bytes, bytes) -> bytes
868 return (
869 _NTLM_post_build(
870 self,
871 pkt,
872 32 + 22 + len(self.Setup) * 2,
873 {
874 "Parameter": 7,
875 "Data": 13,
876 },
877 config=_SMB_CONFIG,
878 )
879 + pay
880 )
883bind_top_down(SMB_Header, SMBTransaction_Response, Command=0x25, Flags=0x80)
886# [MS-ADTS] sect 6.3.1.4
888_NETLOGON_opcodes = {
889 0x7: "LOGON_PRIMARY_QUERY",
890 0x12: "LOGON_SAM_LOGON_REQUEST",
891 0x13: "LOGON_SAM_LOGON_RESPONSE",
892 0x15: "LOGON_SAM_USER_UNKNOWN",
893 0x17: "LOGON_SAM_LOGON_RESPONSE_EX",
894 0x19: "LOGON_SAM_USER_UNKNOWN_EX",
895}
897_NV_VERSION = {
898 0x00000001: "V1",
899 0x00000002: "V5",
900 0x00000004: "V5EX",
901 0x00000008: "V5EX_WITH_IP",
902 0x00000010: "V5EX_WITH_CLOSEST_SITE",
903 0x01000000: "AVOID_NT4EMUL",
904 0x10000000: "PDC",
905 0x20000000: "IP",
906 0x40000000: "LOCAL",
907 0x80000000: "GC",
908}
911class NETLOGON(Packet):
912 @classmethod
913 def dispatch_hook(cls, _pkt=None, *args, **kargs):
914 if _pkt:
915 if _pkt[0] == 0x07: # LOGON_PRIMARY_QUERY
916 return NETLOGON_LOGON_QUERY
917 elif _pkt[0] == 0x12: # LOGON_SAM_LOGON_REQUEST
918 return NETLOGON_SAM_LOGON_REQUEST
919 elif _pkt[0] == 0x13: # LOGON_SAM_USER_RESPONSE
920 try:
921 i = _pkt.index(b"\xff\xff\xff\xff")
922 NtVersion = (
923 NETLOGON_SAM_LOGON_RESPONSE_NT40.fields_desc[-3].getfield(
924 None, _pkt[i - 4:i]
925 )[1]
926 )
927 if NtVersion.V1 and not NtVersion.V5:
928 return NETLOGON_SAM_LOGON_RESPONSE_NT40
929 except Exception:
930 pass
931 return NETLOGON_SAM_LOGON_RESPONSE
932 elif _pkt[0] == 0x15: # LOGON_SAM_USER_UNKNOWN
933 return NETLOGON_SAM_LOGON_RESPONSE
934 elif _pkt[0] == 0x17: # LOGON_SAM_LOGON_RESPONSE_EX
935 return NETLOGON_SAM_LOGON_RESPONSE_EX
936 elif _pkt[0] == 0x19: # LOGON_SAM_USER_UNKNOWN_EX
937 return NETLOGON_SAM_LOGON_RESPONSE
938 return cls
941class NETLOGON_LOGON_QUERY(NETLOGON):
942 fields_desc = [
943 LEShortEnumField("OpCode", 0x7, _NETLOGON_opcodes),
944 StrNullField("ComputerName", ""),
945 StrNullField("MailslotName", ""),
946 StrNullFieldUtf16("UnicodeComputerName", ""),
947 FlagsField("NtVersion", 0xB, -32, _NV_VERSION),
948 XLEShortField("LmNtToken", 0xFFFF),
949 XLEShortField("Lm20Token", 0xFFFF),
950 ]
953# [MS-ADTS] sect 6.3.1.6
956class NETLOGON_SAM_LOGON_REQUEST(NETLOGON):
957 fields_desc = [
958 LEShortEnumField("OpCode", 0x12, _NETLOGON_opcodes),
959 LEShortField("RequestCount", 0),
960 StrNullFieldUtf16("UnicodeComputerName", ""),
961 StrNullFieldUtf16("UnicodeUserName", ""),
962 StrNullField("MailslotName", "\\MAILSLOT\\NET\\GETDC701253F9"),
963 LEIntField("AllowableAccountControlBits", 0),
964 FieldLenField("DomainSidSize", None, fmt="<I", length_of="DomainSid"),
965 XStrLenField("DomainSid", b"", length_from=lambda pkt: pkt.DomainSidSize),
966 FlagsField("NtVersion", 0xB, -32, _NV_VERSION),
967 XLEShortField("LmNtToken", 0xFFFF),
968 XLEShortField("Lm20Token", 0xFFFF),
969 ]
972# [MS-ADTS] sect 6.3.1.7
975class NETLOGON_SAM_LOGON_RESPONSE_NT40(NETLOGON):
976 fields_desc = [
977 LEShortEnumField("OpCode", 0x13, _NETLOGON_opcodes),
978 StrNullFieldUtf16("UnicodeLogonServer", ""),
979 StrNullFieldUtf16("UnicodeUserName", ""),
980 StrNullFieldUtf16("UnicodeDomainName", ""),
981 FlagsField("NtVersion", 0x1, -32, _NV_VERSION),
982 XLEShortField("LmNtToken", 0xFFFF),
983 XLEShortField("Lm20Token", 0xFFFF),
984 ]
987# [MS-ADTS] sect 6.3.1.2
990_NETLOGON_FLAGS = {
991 0x00000001: "PDC",
992 0x00000004: "GC",
993 0x00000008: "LDAP",
994 0x00000010: "DC",
995 0x00000020: "KDC",
996 0x00000040: "TIMESERV",
997 0x00000080: "CLOSEST",
998 0x00000100: "RODC",
999 0x00000200: "GOOD_TIMESERV",
1000 0x00000400: "NC",
1001 0x00000800: "SELECT_SECRET_DOMAIN_6",
1002 0x00001000: "FULL_SECRET_DOMAIN_6",
1003 0x00002000: "WS",
1004 0x00004000: "DS_8",
1005 0x00008000: "DS_9",
1006 0x00010000: "DS_10", # guess
1007 0x00020000: "DS_11", # guess
1008 0x20000000: "DNS_CONTROLLER",
1009 0x40000000: "DNS_DOMAIN",
1010 0x80000000: "DNS_FOREST",
1011}
1014# [MS-ADTS] sect 6.3.1.8
1016class NETLOGON_SAM_LOGON_RESPONSE(NETLOGON, DNSCompressedPacket):
1017 fields_desc = [
1018 LEShortEnumField("OpCode", 0x17, _NETLOGON_opcodes),
1019 StrNullFieldUtf16("UnicodeLogonServer", ""),
1020 StrNullFieldUtf16("UnicodeUserName", ""),
1021 StrNullFieldUtf16("UnicodeDomainName", ""),
1022 UUIDField("DomainGuid", None, uuid_fmt=UUIDField.FORMAT_LE),
1023 UUIDField("NullGuid", None, uuid_fmt=UUIDField.FORMAT_LE),
1024 DNSStrField("DnsForestName", ""),
1025 DNSStrField("DnsDomainName", ""),
1026 DNSStrField("DnsHostName", ""),
1027 IPField("DcIpAddress", "0.0.0.0"),
1028 FlagsField("Flags", 0, -32, _NETLOGON_FLAGS),
1029 FlagsField("NtVersion", 0x1, -32, _NV_VERSION),
1030 XLEShortField("LmNtToken", 0xFFFF),
1031 XLEShortField("Lm20Token", 0xFFFF),
1032 ]
1034 def get_full(self):
1035 return self.original
1038# [MS-ADTS] sect 6.3.1.9
1041class DcSockAddr(Packet):
1042 fields_desc = [
1043 LEShortField("sin_family", 2),
1044 LEShortField("sin_port", 0),
1045 IPField("sin_addr", None),
1046 LELongField("sin_zero", 0),
1047 ]
1049 def default_payload_class(self, payload):
1050 return conf.padding_layer
1053class NETLOGON_SAM_LOGON_RESPONSE_EX(NETLOGON, DNSCompressedPacket):
1054 fields_desc = [
1055 LEShortEnumField("OpCode", 0x17, _NETLOGON_opcodes),
1056 LEShortField("Sbz", 0),
1057 FlagsField("Flags", 0, -32, _NETLOGON_FLAGS),
1058 UUIDField("DomainGuid", None, uuid_fmt=UUIDField.FORMAT_LE),
1059 DNSStrField("DnsForestName", ""),
1060 DNSStrField("DnsDomainName", ""),
1061 DNSStrField("DnsHostName", ""),
1062 DNSStrField("NetbiosDomainName", ""),
1063 DNSStrField("NetbiosComputerName", ""),
1064 DNSStrField("UserName", ""),
1065 DNSStrField("DcSiteName", "Default-First-Site-Name"),
1066 DNSStrField("ClientSiteName", "Default-First-Site-Name"),
1067 ConditionalField(
1068 ByteField("DcSockAddrSize", 0x10),
1069 lambda pkt: pkt.NtVersion.V5EX_WITH_IP,
1070 ),
1071 ConditionalField(
1072 PacketField("DcSockAddr", DcSockAddr(), DcSockAddr),
1073 lambda pkt: pkt.NtVersion.V5EX_WITH_IP,
1074 ),
1075 ConditionalField(
1076 DNSStrField("NextClosestSiteName", ""),
1077 lambda pkt: pkt.NtVersion.V5EX_WITH_CLOSEST_SITE,
1078 ),
1079 FlagsField("NtVersion", 0xB, -32, _NV_VERSION),
1080 XLEShortField("LmNtToken", 0xFFFF),
1081 XLEShortField("Lm20Token", 0xFFFF),
1082 ]
1084 def pre_dissect(self, s):
1085 try:
1086 i = s.index(b"\xff\xff\xff\xff")
1087 self.fields["NtVersion"] = self.fields_desc[-3].getfield(
1088 self,
1089 s[i - 4:i]
1090 )[1]
1091 except Exception:
1092 self.NtVersion = 0xB
1093 return s
1095 def get_full(self):
1096 return self.original
1099# [MS-BRWS] sect 2.2
1101class BRWS(Packet):
1102 fields_desc = [
1103 ByteEnumField("OpCode", 0x00, {
1104 0x01: "HostAnnouncement",
1105 0x02: "AnnouncementRequest",
1106 0x08: "RequestElection",
1107 0x09: "GetBackupListRequest",
1108 0x0A: "GetBackupListResponse",
1109 0x0B: "BecomeBackup",
1110 0x0C: "DomainAnnouncement",
1111 0x0D: "MasterAnnouncement",
1112 0x0E: "ResetStateRequest",
1113 0x0F: "LocalMasterAnnouncement",
1114 }),
1115 ]
1117 def mysummary(self):
1118 return self.sprintf("%OpCode%")
1120 registered_opcodes = {}
1122 @classmethod
1123 def register_variant(cls):
1124 cls.registered_opcodes[cls.OpCode.default] = cls
1126 @classmethod
1127 def dispatch_hook(cls, _pkt=None, *args, **kargs):
1128 if _pkt:
1129 return cls.registered_opcodes.get(_pkt[0], cls)
1130 return cls
1132 def default_payload_class(self, payload):
1133 return conf.padding_layer
1136# [MS-BRWS] sect 2.2.1
1138class BRWS_HostAnnouncement(BRWS):
1139 OpCode = 0x01
1140 fields_desc = [
1141 BRWS,
1142 ByteField("UpdateCount", 0),
1143 LEIntField("Periodicity", 128000),
1144 StrFixedLenField("ServerName", b"", length=16),
1145 ByteField("OSVersionMajor", 6),
1146 ByteField("OSVersionMinor", 1),
1147 LEIntField("ServerType", 4611),
1148 ByteField("BrowserConfigVersionMajor", 21),
1149 ByteField("BrowserConfigVersionMinor", 1),
1150 XLEShortField("Signature", 0xAA55),
1151 StrNullField("Comment", ""),
1152 ]
1154 def mysummary(self):
1155 return self.sprintf("%OpCode% for %ServerName%")
1158# [MS-BRWS] sect 2.2.6
1160class BRWS_BecomeBackup(BRWS):
1161 OpCode = 0x0B
1162 fields_desc = [
1163 BRWS,
1164 StrNullField("BrowserToPromote", b""),
1165 ]
1167 def mysummary(self):
1168 return self.sprintf("%OpCode% from %BrowserToPromote%")
1171# [MS-BRWS] sect 2.2.10
1173class BRWS_LocalMasterAnnouncement(BRWS_HostAnnouncement):
1174 OpCode = 0x0F
1177# SMB dispatcher
1180class _SMBGeneric(Packet):
1181 name = "SMB Generic dispatcher"
1182 fields_desc = [StrFixedLenField("Start", b"\xffSMB", 4)]
1184 @classmethod
1185 def dispatch_hook(cls, _pkt=None, *args, **kargs):
1186 """
1187 Depending on the first 4 bytes of the packet,
1188 dispatch to the correct version of Header
1189 (either SMB or SMB2)
1190 """
1191 if _pkt and len(_pkt) >= 4:
1192 if _pkt[:4] == b"\xffSMB":
1193 return SMB_Header
1194 if _pkt[:4] == b"\xfeSMB":
1195 return SMB2_Header
1196 return cls
1199bind_layers(NBTSession, _SMBGeneric)
1200bind_layers(NBTDatagram, _SMBGeneric)