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 6 7""" 8SMB 1.0 (Server Message Block), also known as CIFS. 9 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>`_ 13 14Specs: 15 16- [MS-CIFS] (base) 17- [MS-SMB] (extension of CIFS - SMB v1) 18""" 19 20import struct 21 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) 53 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) 72 73 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} 151 152 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 ] 205 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) 252 253 def answers(self, pkt): 254 return SMB_Header in pkt 255 256 257# SMB Negotiate Request 258 259 260class SMB_Dialect(Packet): 261 name = "SMB Dialect" 262 fields_desc = [ 263 ByteField("BufferFormat", 0x02), 264 StrNullField("DialectString", "NT LM 0.12"), 265 ] 266 267 def default_payload_class(self, payload): 268 return conf.padding_layer 269 270 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 ] 283 284 285bind_layers(SMB_Header, SMBNegotiate_Request, Command=0x72) 286 287# SMBNegociate Protocol Response 288 289 290def _SMBStrNullField(name, default): 291 """ 292 Returns a StrNullField that is either normal or UTF-16 depending 293 on the SMB headers. 294 """ 295 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 300 301 return MultipleTypeField( 302 [(StrNullFieldUtf16(name, default), _isUTF16)], 303 StrNullField(name, default), 304 ) 305 306 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"")) 313 314 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 334 335 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] 370 371 372# CIFS sect 2.2.4.52.2 373 374 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 ] 425 426 427bind_top_down(SMB_Header, SMBNegotiate_Response_NoSecurity, Command=0x72, Flags=0x80) 428 429# SMB sect 2.2.4.5.2.1 430 431 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 ] 445 446 447bind_top_down( 448 SMB_Header, 449 SMBNegotiate_Response_Extended_Security, 450 Command=0x72, 451 Flags=0x80, 452 Flags2=0x800, 453) 454 455# SMB sect 2.2.4.5.2.2 456 457 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 ] 479 480 481bind_top_down(SMB_Header, SMBNegotiate_Response_Security, Command=0x72, Flags=0x80) 482 483# Session Setup AndX Request 484 485# CIFS sect 2.2.4.53 486 487 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 ] 513 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 522 523 524bind_top_down(SMB_Header, SMBSession_Setup_AndX_Request, Command=0x73) 525 526# SMB sect 2.2.4.7 527 528 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 ] 545 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 551 552 553bind_layers(SMB_Header, SMBTree_Connect_AndX, Command=0x75) 554bind_layers(SMBSession_Setup_AndX_Request, SMBTree_Connect_AndX, AndXCommand=0x75) 555 556# SMB sect 2.2.4.6.1 557 558 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 ) 584 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 589 590 591bind_top_down( 592 SMB_Header, 593 SMBSession_Setup_AndX_Request_Extended_Security, 594 Command=0x73, 595 Flags2=0x800, 596) 597 598# Session Setup AndX Response 599 600 601# CIFS sect 2.2.4.53.2 602 603 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 ] 634 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 639 640 641bind_top_down(SMB_Header, SMBSession_Setup_AndX_Response, Command=0x73, Flags=0x80) 642 643# SMB sect 2.2.4.6.2 644 645 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 ) 656 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 ) 663 664 665bind_top_down( 666 SMB_Header, 667 SMBSession_Setup_AndX_Response_Extended_Security, 668 Command=0x73, 669 Flags=0x80, 670 Flags2=0x800, 671) 672 673# SMB null (no wordcount) 674 675 676class SMBSession_Null(Packet): 677 fields_desc = [ByteField("WordCount", 0), LEShortField("ByteCount", 0)] 678 679 680bind_top_down(SMB_Header, SMBSession_Null, Command=0x73) 681 682# [MS-CIFS] sect 2.2.4.33.1 683 684_SMB_CONFIG = [ 685 ("Len", _NTLM_ENUM.LEN), 686 ("BufferOffset", _NTLM_ENUM.OFFSET), 687] 688 689 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) 697 698 699def _optlen(pkt, x): 700 try: 701 return len(getattr(pkt, x)) 702 except AttributeError: 703 return 0 704 705 706class SMBTransaction_Request(_NTLMPayloadPacket): 707 name = "SMB COM Transaction Request" 708 _NTLM_PAYLOAD_FIELD_NAME = "Buffer" 709 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 ] 773 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 ) 789 790 def mysummary(self): 791 if getattr(self, "Data", None) is not None: 792 return self.sprintf("Tran %Name% ") + self.Data.mysummary() 793 return self.sprintf("Tran %Name%") 794 795 796bind_top_down(SMB_Header, SMBTransaction_Request, Command=0x25) 797 798 799class SMBMailslot_Write(SMBTransaction_Request): 800 WordCount = 0x11 801 802 803# [MS-CIFS] sect 2.2.4.33.2 804 805 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 ] 865 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 ) 881 882 883bind_top_down(SMB_Header, SMBTransaction_Response, Command=0x25, Flags=0x80) 884 885 886# [MS-ADTS] sect 6.3.1.4 887 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} 896 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} 909 910 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 939 940 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 ] 951 952 953# [MS-ADTS] sect 6.3.1.6 954 955 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 ] 970 971 972# [MS-ADTS] sect 6.3.1.7 973 974 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 ] 985 986 987# [MS-ADTS] sect 6.3.1.2 988 989 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} 1012 1013 1014# [MS-ADTS] sect 6.3.1.8 1015 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 ] 1033 1034 def get_full(self): 1035 return self.original 1036 1037 1038# [MS-ADTS] sect 6.3.1.9 1039 1040 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 ] 1048 1049 def default_payload_class(self, payload): 1050 return conf.padding_layer 1051 1052 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 ] 1083 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 1094 1095 def get_full(self): 1096 return self.original 1097 1098 1099# [MS-BRWS] sect 2.2 1100 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 ] 1116 1117 def mysummary(self): 1118 return self.sprintf("%OpCode%") 1119 1120 registered_opcodes = {} 1121 1122 @classmethod 1123 def register_variant(cls): 1124 cls.registered_opcodes[cls.OpCode.default] = cls 1125 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 1131 1132 def default_payload_class(self, payload): 1133 return conf.padding_layer 1134 1135 1136# [MS-BRWS] sect 2.2.1 1137 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 ] 1153 1154 def mysummary(self): 1155 return self.sprintf("%OpCode% for %ServerName%") 1156 1157 1158# [MS-BRWS] sect 2.2.6 1159 1160class BRWS_BecomeBackup(BRWS): 1161 OpCode = 0x0B 1162 fields_desc = [ 1163 BRWS, 1164 StrNullField("BrowserToPromote", b""), 1165 ] 1166 1167 def mysummary(self): 1168 return self.sprintf("%OpCode% from %BrowserToPromote%") 1169 1170 1171# [MS-BRWS] sect 2.2.10 1172 1173class BRWS_LocalMasterAnnouncement(BRWS_HostAnnouncement): 1174 OpCode = 0x0F 1175 1176 1177# SMB dispatcher 1178 1179 1180class _SMBGeneric(Packet): 1181 name = "SMB Generic dispatcher" 1182 fields_desc = [StrFixedLenField("Start", b"\xffSMB", 4)] 1183 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 1197 1198 1199bind_layers(NBTSession, _SMBGeneric) 1200bind_layers(NBTDatagram, _SMBGeneric) 1201