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""" 7[MS-PAC] 8 9https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/166d8064-c863-41e1-9c23-edaaa5f36962 10Up to date with version: 23.0 11""" 12 13import struct 14 15from scapy.config import conf 16from scapy.error import log_runtime 17from scapy.fields import ( 18 ConditionalField, 19 FieldLenField, 20 FieldListField, 21 FlagsField, 22 LEIntEnumField, 23 LELongField, 24 LEIntField, 25 LEShortField, 26 MultipleTypeField, 27 PacketField, 28 PacketListField, 29 StrField, 30 StrFieldUtf16, 31 StrFixedLenField, 32 StrLenFieldUtf16, 33 UTCTimeField, 34 XStrField, 35 XStrLenField, 36) 37from scapy.packet import Packet 38from scapy.layers.kerberos import ( 39 _AUTHORIZATIONDATA_VALUES, 40 _KRB_S_TYPES, 41) 42from scapy.layers.dcerpc import ( 43 NDRByteField, 44 NDRConfFieldListField, 45 NDRConfPacketListField, 46 NDRConfStrLenField, 47 NDRConfVarStrLenFieldUtf16, 48 NDRConfVarStrNullFieldUtf16, 49 NDRConformantString, 50 NDRFieldListField, 51 NDRFullPointerField, 52 NDRInt3264EnumField, 53 NDRIntField, 54 NDRLongField, 55 NDRPacket, 56 NDRPacketField, 57 NDRSerialization1Header, 58 NDRSerializeType1PacketLenField, 59 NDRShortField, 60 NDRSignedLongField, 61 NDRUnionField, 62 _NDRConfField, 63 ndr_deserialize1, 64 ndr_serialize1, 65) 66from scapy.layers.ntlm import ( 67 _NTLMPayloadField, 68 _NTLMPayloadPacket, 69) 70from scapy.layers.smb2 import WINNT_SID 71 72# sect 2.4 73 74 75class PAC_INFO_BUFFER(Packet): 76 fields_desc = [ 77 LEIntEnumField( 78 "ulType", 79 0x00000001, 80 { 81 0x00000001: "Logon information", 82 0x00000002: "Credentials information", 83 0x00000006: "Server Signature", 84 0x00000007: "KDC Signature", 85 0x0000000A: "Client name and ticket information", 86 0x0000000B: "Constrained delegation information", 87 0x0000000C: "UPN and DNS information", 88 0x0000000D: "Client claims information", 89 0x0000000E: "Device information", 90 0x0000000F: "Device claims information", 91 0x00000010: "Ticket Signature", 92 0x00000011: "PAC Attributes", 93 0x00000012: "PAC Requestor", 94 0x00000013: "Extended KDC Signature", 95 }, 96 ), 97 LEIntField("cbBufferSize", None), 98 LELongField("Offset", None), 99 ] 100 101 def default_payload_class(self, payload): 102 return conf.padding_layer 103 104 105_PACTYPES = {} 106 107 108# sect 2.5 - NDR PACKETS 109 110 111class RPC_UNICODE_STRING(NDRPacket): 112 ALIGNMENT = (4, 8) 113 fields_desc = [ 114 NDRShortField("Length", None, size_of="Buffer", adjust=lambda _, x: (x * 2)), 115 NDRShortField( 116 "MaximumLength", None, size_of="Buffer", adjust=lambda _, x: (x * 2) 117 ), 118 NDRFullPointerField( 119 NDRConfVarStrLenFieldUtf16( 120 "Buffer", 121 "", 122 size_is=lambda pkt: (pkt.MaximumLength // 2), 123 length_is=lambda pkt: (pkt.Length // 2), 124 ), 125 deferred=True, 126 ), 127 ] 128 129 130class FILETIME(NDRPacket): 131 ALIGNMENT = (4, 4) 132 fields_desc = [NDRIntField("dwLowDateTime", 0), NDRIntField("dwHighDateTime", 0)] 133 134 135class GROUP_MEMBERSHIP(NDRPacket): 136 ALIGNMENT = (4, 4) 137 fields_desc = [NDRIntField("RelativeId", 0), NDRIntField("Attributes", 0)] 138 139 140class CYPHER_BLOCK(NDRPacket): 141 fields_desc = [StrFixedLenField("data", "", length=8)] 142 143 144class USER_SESSION_KEY(NDRPacket): 145 fields_desc = [PacketListField("data", [], CYPHER_BLOCK, count_from=lambda _: 2)] 146 147 148class RPC_SID_IDENTIFIER_AUTHORITY(NDRPacket): 149 fields_desc = [StrFixedLenField("Value", "", length=6)] 150 151 152class SID(NDRPacket): 153 ALIGNMENT = (4, 8) 154 DEPORTED_CONFORMANTS = ["SubAuthority"] 155 fields_desc = [ 156 NDRByteField("Revision", 0), 157 NDRByteField("SubAuthorityCount", None, size_of="SubAuthority"), 158 NDRPacketField( 159 "IdentifierAuthority", 160 RPC_SID_IDENTIFIER_AUTHORITY(), 161 RPC_SID_IDENTIFIER_AUTHORITY, 162 ), 163 NDRConfFieldListField( 164 "SubAuthority", 165 [], 166 NDRIntField("", 0), 167 size_is=lambda pkt: pkt.SubAuthorityCount, 168 conformant_in_struct=True, 169 ), 170 ] 171 172 def summary(self): 173 return WINNT_SID.summary(self) 174 175 176class KERB_SID_AND_ATTRIBUTES(NDRPacket): 177 ALIGNMENT = (4, 8) 178 fields_desc = [ 179 NDRFullPointerField(NDRPacketField("Sid", SID(), SID), deferred=True), 180 NDRIntField("Attributes", 0), 181 ] 182 183 184class KERB_VALIDATION_INFO(NDRPacket): 185 ALIGNMENT = (4, 8) 186 fields_desc = [ 187 NDRPacketField("LogonTime", FILETIME(), FILETIME), 188 NDRPacketField("LogoffTime", FILETIME(), FILETIME), 189 NDRPacketField("KickOffTime", FILETIME(), FILETIME), 190 NDRPacketField("PasswordLastSet", FILETIME(), FILETIME), 191 NDRPacketField("PasswordCanChange", FILETIME(), FILETIME), 192 NDRPacketField("PasswordMustChange", FILETIME(), FILETIME), 193 NDRPacketField("EffectiveName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 194 NDRPacketField("FullName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 195 NDRPacketField("LogonScript", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 196 NDRPacketField("ProfilePath", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 197 NDRPacketField("HomeDirectory", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 198 NDRPacketField("HomeDirectoryDrive", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 199 NDRShortField("LogonCount", 0), 200 NDRShortField("BadPasswordCount", 0), 201 NDRIntField("UserId", 0), 202 NDRIntField("PrimaryGroupId", 0), 203 NDRIntField("GroupCount", None, size_of="GroupIds"), 204 NDRFullPointerField( 205 NDRConfPacketListField( 206 "GroupIds", 207 [GROUP_MEMBERSHIP()], 208 GROUP_MEMBERSHIP, 209 size_is=lambda pkt: pkt.GroupCount, 210 ), 211 deferred=True, 212 ), 213 NDRIntField("UserFlags", 0), 214 NDRPacketField("UserSessionKey", USER_SESSION_KEY(), USER_SESSION_KEY), 215 NDRPacketField("LogonServer", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 216 NDRPacketField("LogonDomainName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 217 NDRFullPointerField(NDRPacketField("LogonDomainId", SID(), SID), deferred=True), 218 NDRFieldListField("Reserved1", [], NDRIntField("", 0), length_is=lambda _: 2), 219 NDRIntField("UserAccountControl", 0), 220 NDRFieldListField("Reserved3", [], NDRIntField("", 0), length_is=lambda _: 7), 221 NDRIntField("SidCount", None, size_of="ExtraSids"), 222 NDRFullPointerField( 223 NDRConfPacketListField( 224 "ExtraSids", 225 [KERB_SID_AND_ATTRIBUTES()], 226 KERB_SID_AND_ATTRIBUTES, 227 size_is=lambda pkt: pkt.SidCount, 228 ), 229 deferred=True, 230 ), 231 NDRFullPointerField( 232 NDRPacketField("ResourceGroupDomainSid", SID(), SID), deferred=True 233 ), 234 NDRIntField("ResourceGroupCount", None, size_of="ResourceGroupIds"), 235 NDRFullPointerField( 236 NDRConfPacketListField( 237 "ResourceGroupIds", 238 [GROUP_MEMBERSHIP()], 239 GROUP_MEMBERSHIP, 240 size_is=lambda pkt: pkt.ResourceGroupCount, 241 ), 242 deferred=True, 243 ), 244 ] 245 246 247_PACTYPES[1] = KERB_VALIDATION_INFO 248 249# sect 2.6 250 251 252class PAC_CREDENTIAL_INFO(Packet): 253 fields_desc = [ 254 LEIntField("Version", 0), 255 LEIntEnumField( 256 "EncryptionType", 257 1, 258 { 259 0x00000001: "DES-CBC-CRC", 260 0x00000003: "DES-CBC-MD5", 261 0x00000011: "AES128_CTS_HMAC_SHA1_96", 262 0x00000012: "AES256_CTS_HMAC_SHA1_96", 263 0x00000017: "RC4-HMAC", 264 }, 265 ), 266 XStrField("SerializedData", b""), 267 ] 268 269 270_PACTYPES[2] = PAC_CREDENTIAL_INFO 271 272# sect 2.7 273 274 275class PAC_CLIENT_INFO(Packet): 276 fields_desc = [ 277 UTCTimeField( 278 "ClientId", None, fmt="<Q", epoch=[1601, 1, 1, 0, 0, 0], custom_scaling=1e7 279 ), 280 FieldLenField("NameLength", None, length_of="Name", fmt="<H"), 281 StrLenFieldUtf16("Name", b"", length_from=lambda pkt: pkt.NameLength), 282 ] 283 284 285_PACTYPES[0xA] = PAC_CLIENT_INFO 286 287# sect 2.8 288 289 290class PAC_SIGNATURE_DATA(Packet): 291 fields_desc = [ 292 LEIntEnumField( 293 "SignatureType", 294 None, 295 _KRB_S_TYPES, 296 ), 297 XStrLenField( 298 "Signature", 299 b"", 300 length_from=lambda pkt: { 301 0x1: 4, 302 0xFFFFFF76: 16, 303 0x0000000F: 12, 304 0x00000010: 12, 305 }.get(pkt.SignatureType, 0), 306 ), 307 StrField("RODCIdentifier", b""), 308 ] 309 310 311_PACTYPES[6] = PAC_SIGNATURE_DATA 312_PACTYPES[7] = PAC_SIGNATURE_DATA 313_PACTYPES[0x10] = PAC_SIGNATURE_DATA 314_PACTYPES[0x13] = PAC_SIGNATURE_DATA 315 316# sect 2.9 317 318 319class S4U_DELEGATION_INFO(NDRPacket): 320 ALIGNMENT = (4, 8) 321 fields_desc = [ 322 NDRPacketField("S4U2proxyTarget", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), 323 NDRIntField("TransitedListSize", None, size_of="S4UTransitedServices"), 324 NDRFullPointerField( 325 NDRConfPacketListField( 326 "S4UTransitedServices", 327 [RPC_UNICODE_STRING()], 328 RPC_UNICODE_STRING, 329 size_is=lambda pkt: pkt.TransitedListSize, 330 ), 331 deferred=True, 332 ), 333 ] 334 335 336# sect 2.10 337 338 339def _pac_post_build(self, p, pay_offset, fields): 340 """Util function to build the offset and populate the lengths""" 341 for field_name, value in self.fields["Payload"]: 342 length = self.get_field("Payload").fields_map[field_name].i2len(self, value) 343 offset = fields[field_name] 344 # Length 345 if self.getfieldval(field_name + "Len") is None: 346 p = p[:offset] + struct.pack("<H", length) + p[offset + 2 :] 347 # Offset 348 if self.getfieldval(field_name + "BufferOffset") is None: 349 p = p[: offset + 2] + struct.pack("<H", pay_offset) + p[offset + 4 :] 350 pay_offset += length 351 return p 352 353 354class UPN_DNS_INFO(_NTLMPayloadPacket): 355 fields_desc = [ 356 LEShortField("UpnLen", None), 357 LEShortField("UpnBufferOffset", None), 358 LEShortField("DnsDomainNameLen", None), 359 LEShortField("DnsDomainNameBufferOffset", None), 360 FlagsField( 361 "Flags", 362 0, 363 -32, 364 [ 365 "U", 366 "S", # Extended 367 ], 368 ), 369 ConditionalField( 370 # Extended 371 LEShortField("SamNameLen", None), 372 lambda pkt: pkt.Flags.S, 373 ), 374 ConditionalField( 375 # Extended 376 LEShortField("SamNameBufferOffset", None), 377 lambda pkt: pkt.Flags.S, 378 ), 379 ConditionalField( 380 # Extended 381 LEShortField("SidLen", None), 382 lambda pkt: pkt.Flags.S, 383 ), 384 ConditionalField( 385 # Extended 386 LEShortField("SidBufferOffset", None), 387 lambda pkt: pkt.Flags.S, 388 ), 389 MultipleTypeField( 390 [ 391 ( 392 # Extended 393 _NTLMPayloadField( 394 "Payload", 395 20, 396 [ 397 StrFieldUtf16("Upn", b""), 398 StrFieldUtf16("DnsDomainName", b""), 399 StrFieldUtf16("SamName", b""), 400 PacketField("Sid", WINNT_SID(), WINNT_SID), 401 ], 402 ), 403 lambda pkt: pkt.Flags.S, 404 ) 405 ], 406 # Not-extended 407 _NTLMPayloadField( 408 "Payload", 409 12, 410 [ 411 StrFieldUtf16("Upn", b""), 412 StrFieldUtf16("DnsDomainName", b""), 413 ], 414 ), 415 ), 416 ] 417 418 def post_build(self, pkt, pay): 419 # type: (bytes, bytes) -> bytes 420 offset = 12 421 fields = { 422 "Upn": 0, 423 "DnsDomainName": 4, 424 } 425 if self.Flags.S: 426 offset = 20 427 fields["SamName"] = 12 428 fields["Sid"] = 16 429 return ( 430 _pac_post_build( 431 self, 432 pkt, 433 offset, 434 fields, 435 ) 436 + pay 437 ) 438 439 440_PACTYPES[0xC] = UPN_DNS_INFO 441 442# sect 2.11 - NDR PACKETS 443 444try: 445 from enum import IntEnum 446except ImportError: 447 IntEnum = object 448 449 450class CLAIM_TYPE(IntEnum): 451 CLAIM_TYPE_INT64 = 1 452 CLAIM_TYPE_UINT64 = 2 453 CLAIM_TYPE_STRING = 3 454 CLAIM_TYPE_BOOLEAN = 6 455 456 457class CLAIMS_SOURCE_TYPE(IntEnum): 458 CLAIMS_SOURCE_TYPE_AD = 1 459 CLAIMS_SOURCE_TYPE_CERTIFICATE = 2 460 461 462class CLAIMS_COMPRESSION_FORMAT(IntEnum): 463 COMPRESSION_FORMAT_NONE = 0 464 COMPRESSION_FORMAT_LZNT1 = 2 465 COMPRESSION_FORMAT_XPRESS = 3 466 COMPRESSION_FORMAT_XPRESS_HUFF = 4 467 468 469class CLAIM_ENTRY_sub0(NDRPacket): 470 ALIGNMENT = (4, 8) 471 fields_desc = [ 472 NDRIntField("ValueCount", None, size_of="Int64Values"), 473 NDRFullPointerField( 474 NDRConfFieldListField( 475 "Int64Values", 476 [], 477 NDRSignedLongField, 478 size_is=lambda pkt: pkt.ValueCount, 479 ), 480 deferred=True, 481 ), 482 ] 483 484 485class CLAIM_ENTRY_sub1(NDRPacket): 486 ALIGNMENT = (4, 8) 487 fields_desc = [ 488 NDRIntField("ValueCount", None, size_of="Uint64Values"), 489 NDRFullPointerField( 490 NDRConfFieldListField( 491 "Uint64Values", [], NDRLongField, size_is=lambda pkt: pkt.ValueCount 492 ), 493 deferred=True, 494 ), 495 ] 496 497 498class CLAIM_ENTRY_sub2(NDRPacket): 499 ALIGNMENT = (4, 8) 500 fields_desc = [ 501 NDRIntField("ValueCount", None, size_of="StringValues"), 502 NDRFullPointerField( 503 NDRConfFieldListField( 504 "StringValues", 505 [], 506 NDRFullPointerField( 507 NDRConfVarStrNullFieldUtf16("StringVal", ""), 508 deferred=True, 509 ), 510 size_is=lambda pkt: pkt.ValueCount, 511 ), 512 deferred=True, 513 ), 514 ] 515 516 517class CLAIM_ENTRY_sub3(NDRPacket): 518 ALIGNMENT = (4, 8) 519 fields_desc = [ 520 NDRIntField("ValueCount", None, size_of="BooleanValues"), 521 NDRFullPointerField( 522 NDRConfFieldListField( 523 "BooleanValues", [], NDRLongField, size_is=lambda pkt: pkt.ValueCount 524 ), 525 deferred=True, 526 ), 527 ] 528 529 530class CLAIM_ENTRY(NDRPacket): 531 ALIGNMENT = (4, 8) 532 fields_desc = [ 533 NDRFullPointerField(NDRConfVarStrNullFieldUtf16("Id", ""), deferred=True), 534 NDRInt3264EnumField("Type", 0, CLAIM_TYPE), 535 NDRUnionField( 536 [ 537 ( 538 NDRPacketField("Values", CLAIM_ENTRY_sub0(), CLAIM_ENTRY_sub0), 539 ( 540 ( 541 lambda pkt: getattr(pkt, "Type", None) 542 == CLAIM_TYPE.CLAIM_TYPE_INT64 543 ), 544 (lambda _, val: val.tag == CLAIM_TYPE.CLAIM_TYPE_INT64), 545 ), 546 ), 547 ( 548 NDRPacketField("Values", CLAIM_ENTRY_sub1(), CLAIM_ENTRY_sub1), 549 ( 550 ( 551 lambda pkt: getattr(pkt, "Type", None) 552 == CLAIM_TYPE.CLAIM_TYPE_UINT64 553 ), 554 (lambda _, val: val.tag == CLAIM_TYPE.CLAIM_TYPE_UINT64), 555 ), 556 ), 557 ( 558 NDRPacketField("Values", CLAIM_ENTRY_sub2(), CLAIM_ENTRY_sub2), 559 ( 560 ( 561 lambda pkt: getattr(pkt, "Type", None) 562 == CLAIM_TYPE.CLAIM_TYPE_STRING 563 ), 564 (lambda _, val: val.tag == CLAIM_TYPE.CLAIM_TYPE_STRING), 565 ), 566 ), 567 ( 568 NDRPacketField("Values", CLAIM_ENTRY_sub3(), CLAIM_ENTRY_sub3), 569 ( 570 ( 571 lambda pkt: getattr(pkt, "Type", None) 572 == CLAIM_TYPE.CLAIM_TYPE_BOOLEAN 573 ), 574 (lambda _, val: val.tag == CLAIM_TYPE.CLAIM_TYPE_BOOLEAN), 575 ), 576 ), 577 ], 578 StrFixedLenField("Values", "", length=0), 579 align=(2, 8), 580 switch_fmt=("H", "I"), 581 ), 582 ] 583 584 585class CLAIMS_ARRAY(NDRPacket): 586 ALIGNMENT = (4, 8) 587 fields_desc = [ 588 NDRInt3264EnumField("usClaimsSourceType", 0, CLAIMS_SOURCE_TYPE), 589 NDRIntField("ulClaimsCount", None, size_of="ClaimEntries"), 590 NDRFullPointerField( 591 NDRConfPacketListField( 592 "ClaimEntries", 593 [CLAIM_ENTRY()], 594 CLAIM_ENTRY, 595 size_is=lambda pkt: pkt.ulClaimsCount, 596 ), 597 deferred=True, 598 ), 599 ] 600 601 602class CLAIMS_SET(NDRPacket): 603 ALIGNMENT = (4, 8) 604 fields_desc = [ 605 NDRIntField("ulClaimsArrayCount", None, size_of="ClaimsArrays"), 606 NDRFullPointerField( 607 NDRConfPacketListField( 608 "ClaimsArrays", 609 [CLAIMS_ARRAY()], 610 CLAIMS_ARRAY, 611 size_is=lambda pkt: pkt.ulClaimsArrayCount, 612 ), 613 deferred=True, 614 ), 615 NDRShortField("usReservedType", 0), 616 NDRIntField("ulReservedFieldSize", None, size_of="ReservedField"), 617 NDRFullPointerField( 618 NDRConfStrLenField( 619 "ReservedField", "", size_is=lambda pkt: pkt.ulReservedFieldSize 620 ), 621 deferred=True, 622 ), 623 ] 624 625 626class _CLAIMSClaimSet(_NDRConfField, NDRSerializeType1PacketLenField): 627 CONFORMANT_STRING = True 628 LENGTH_FROM = True 629 630 def m2i(self, pkt, s): 631 if pkt.usCompressionFormat == CLAIMS_COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE: 632 return ndr_deserialize1(s, CLAIMS_SET, ndr64=False) 633 else: 634 # TODO: There are 3 funky compression formats... see sect 2.2.18.4 635 return NDRConformantString(value=s) 636 637 def i2m(self, pkt, val): 638 val = val[0] 639 if pkt.usCompressionFormat == CLAIMS_COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE: 640 return ndr_serialize1(val) 641 else: 642 # funky 643 return bytes(val) 644 645 def valueof(self, pkt, x): 646 if pkt.usCompressionFormat == CLAIMS_COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE: 647 return self._subval(x)[0] 648 else: 649 return x 650 651 652class CLAIMS_SET_METADATA(NDRPacket): 653 ALIGNMENT = (4, 8) 654 fields_desc = [ 655 NDRIntField("ulClaimsSetSize", None, size_of="ClaimsSet"), 656 NDRFullPointerField( 657 _CLAIMSClaimSet( 658 "ClaimsSet", None, None, size_is=lambda pkt: pkt.ulClaimsSetSize 659 ), 660 deferred=True, 661 ), 662 NDRInt3264EnumField( 663 "usCompressionFormat", 664 0, 665 CLAIMS_COMPRESSION_FORMAT, 666 ), 667 # this size_of is technically wrong. we just assume it's uncompressed... 668 NDRIntField("ulUncompressedClaimsSetSize", None, size_of="ClaimsSet"), 669 NDRShortField("usReservedType", 0), 670 NDRIntField("ulReservedFieldSize", None, size_of="ReservedField"), 671 NDRFullPointerField( 672 NDRConfStrLenField( 673 "ReservedField", "", size_is=lambda pkt: pkt.ulReservedFieldSize 674 ), 675 deferred=True, 676 ), 677 ] 678 679 680class PAC_CLIENT_CLAIMS_INFO(NDRPacket): 681 fields_desc = [NDRPacketField("Claims", CLAIMS_SET_METADATA(), CLAIMS_SET_METADATA)] 682 683 684if IntEnum != object: 685 # If not available, ignore. I can't be bothered 686 _PACTYPES[0xD] = PAC_CLIENT_CLAIMS_INFO 687 688 689# sect 2.12 - NDR PACKETS 690 691 692class DOMAIN_GROUP_MEMBERSHIP(NDRPacket): 693 ALIGNMENT = (4, 8) 694 fields_desc = [ 695 NDRFullPointerField(NDRPacketField("DomainId", SID(), SID), deferred=True), 696 NDRIntField("GroupCount", 0), 697 NDRFullPointerField( 698 NDRConfPacketListField( 699 "GroupIds", 700 [GROUP_MEMBERSHIP()], 701 GROUP_MEMBERSHIP, 702 size_is=lambda pkt: pkt.GroupCount, 703 ), 704 deferred=True, 705 ), 706 ] 707 708 709class PAC_DEVICE_INFO(NDRPacket): 710 ALIGNMENT = (4, 8) 711 fields_desc = [ 712 NDRIntField("UserId", 0), 713 NDRIntField("PrimaryGroupId", 0), 714 NDRFullPointerField( 715 NDRPacketField("AccountDomainId", SID(), SID), deferred=True 716 ), 717 NDRIntField("AccountGroupCount", 0), 718 NDRFullPointerField( 719 NDRConfPacketListField( 720 "AccountGroupIds", 721 [GROUP_MEMBERSHIP()], 722 GROUP_MEMBERSHIP, 723 size_is=lambda pkt: pkt.AccountGroupCount, 724 ), 725 deferred=True, 726 ), 727 NDRIntField("SidCount", 0), 728 NDRFullPointerField( 729 NDRConfPacketListField( 730 "ExtraSids", 731 [KERB_SID_AND_ATTRIBUTES()], 732 KERB_SID_AND_ATTRIBUTES, 733 size_is=lambda pkt: pkt.SidCount, 734 ), 735 deferred=True, 736 ), 737 NDRIntField("DomainGroupCount", 0), 738 NDRFullPointerField( 739 NDRConfPacketListField( 740 "DomainGroup", 741 [DOMAIN_GROUP_MEMBERSHIP()], 742 DOMAIN_GROUP_MEMBERSHIP, 743 size_is=lambda pkt: pkt.DomainGroupCount, 744 ), 745 deferred=True, 746 ), 747 ] 748 749 750_PACTYPES[0xE] = PAC_DEVICE_INFO 751 752# sect 2.14 - PAC_ATTRIBUTES_INFO 753 754 755class PAC_ATTRIBUTES_INFO(Packet): 756 fields_desc = [ 757 LEIntField("FlagsLength", 2), 758 FieldListField( 759 "Flags", 760 ["PAC_WAS_REQUESTED"], 761 FlagsField( 762 "", 763 0, 764 -32, 765 { 766 0x00000001: "PAC_WAS_REQUESTED", 767 0x00000002: "PAC_WAS_GIVEN_IMPLICITLY", 768 }, 769 ), 770 count_from=lambda pkt: (pkt.FlagsLength + 7) // 8, 771 ), 772 ] 773 774 775_PACTYPES[0x11] = PAC_ATTRIBUTES_INFO 776 777# sect 2.15 - PAC_REQUESTOR 778 779 780class PAC_REQUESTOR(Packet): 781 fields_desc = [ 782 PacketField("Sid", WINNT_SID(), WINNT_SID), 783 ] 784 785 786_PACTYPES[0x12] = PAC_REQUESTOR 787 788# sect 2.3 789 790 791class _PACTYPEBuffers(PacketListField): 792 def addfield(self, pkt, s, val): 793 # we use this field to set Offset and cbBufferSize 794 res = b"" 795 if len(val) != len(pkt.Payloads): 796 log_runtime.warning("Size of 'Buffers' does not match size of 'Payloads' !") 797 return super(_PACTYPEBuffers, self).addfield(pkt, s, val) 798 offset = 16 * len(pkt.Payloads) + 8 799 for i, v in enumerate(val): 800 x = self.i2m(pkt, v) 801 pay = pkt.Payloads[i] 802 if isinstance(pay, NDRPacket) or isinstance(pay, NDRSerialization1Header): 803 lgth = len(ndr_serialize1(pay)) 804 else: 805 lgth = len(pay) 806 if v.cbBufferSize is None: 807 x = x[:4] + struct.pack("<I", lgth) + x[8:] 808 if v.Offset is None: 809 x = x[:8] + struct.pack("<Q", offset) + x[16:] 810 offset += lgth 811 offset += (-offset) % 8 # Account for padding 812 res += x 813 return s + res 814 815 816class _PACTYPEPayloads(PacketListField): 817 def i2m(self, pkt, val): 818 if isinstance(val, NDRPacket) or isinstance(val, NDRSerialization1Header): 819 s = ndr_serialize1(val) 820 else: 821 s = bytes(val) 822 return s + b"\x00" * ((-len(s)) % 8) 823 824 def getfield(self, pkt, s): 825 if not pkt or not s: 826 return s, [] 827 result = [] 828 for i in range(len(pkt.Buffers)): 829 buf = pkt.Buffers[i] 830 offset = buf.Offset - 16 * len(pkt.Buffers) - 8 831 try: 832 cls = _PACTYPES[buf.ulType] 833 if buf.cbBufferSize == 0: 834 # empty size 835 raise KeyError 836 if issubclass(cls, NDRPacket): 837 val = ndr_deserialize1( 838 s[offset : offset + buf.cbBufferSize], 839 cls, 840 ndr64=False, 841 ) 842 else: 843 val = cls(s[offset : offset + buf.cbBufferSize]) 844 if conf.raw_layer in val: 845 pad = conf.padding_layer(load=val[conf.raw_layer].load) 846 lay = val[conf.raw_layer].underlayer 847 if not lay: 848 val.show() 849 raise ValueError("Dissection failed") 850 lay.remove_payload() 851 lay.add_payload(pad) 852 except KeyError: 853 val = conf.padding_layer(s[offset : offset + buf.cbBufferSize]) 854 result.append(val) 855 return b"", result 856 857 858class PACTYPE(Packet): 859 name = "PACTYPE - PAC" 860 fields_desc = [ 861 FieldLenField("cBuffers", None, count_of="Buffers", fmt="<I"), 862 LEIntField("Version", 0x00000000), 863 _PACTYPEBuffers( 864 "Buffers", 865 [PAC_INFO_BUFFER()], 866 PAC_INFO_BUFFER, 867 count_from=lambda pkt: pkt.cBuffers, 868 ), 869 _PACTYPEPayloads("Payloads", [], None), 870 ] 871 872 873_AUTHORIZATIONDATA_VALUES[128] = PACTYPE # AD-WIN2K-PAC 874