Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/layers/dcerpc.py: 49%

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

1152 statements  

1# SPDX-License-Identifier: GPL-2.0-or-later 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Gabriel Potter 

5 

6# scapy.contrib.description = DCE/RPC 

7# scapy.contrib.status = loads 

8 

9""" 

10DCE/RPC 

11Distributed Computing Environment / Remote Procedure Calls 

12 

13Based on [C706] - aka DCE/RPC 1.1 

14https://pubs.opengroup.org/onlinepubs/9629399/toc.pdf 

15 

16And on [MS-RPCE] 

17https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/290c38b1-92fe-4229-91e6-4fc376610c15 

18 

19.. note:: 

20 Please read the documentation over 

21 `DCE/RPC <https://scapy.readthedocs.io/en/latest/layers/dcerpc.html>`_ 

22""" 

23 

24from functools import partial 

25 

26import collections 

27import struct 

28from enum import IntEnum 

29from uuid import UUID 

30from scapy.base_classes import Packet_metaclass 

31 

32from scapy.config import conf 

33from scapy.compat import bytes_encode, plain_str 

34from scapy.error import log_runtime 

35from scapy.layers.dns import DNSStrField 

36from scapy.layers.ntlm import ( 

37 NTLM_Header, 

38 NTLMSSP_MESSAGE_SIGNATURE, 

39) 

40from scapy.packet import ( 

41 Packet, 

42 Raw, 

43 bind_bottom_up, 

44 bind_layers, 

45 bind_top_down, 

46 NoPayload, 

47) 

48from scapy.fields import ( 

49 _FieldContainer, 

50 BitEnumField, 

51 BitField, 

52 ByteEnumField, 

53 ByteField, 

54 ConditionalField, 

55 EnumField, 

56 Field, 

57 FieldLenField, 

58 FieldListField, 

59 FlagsField, 

60 IntField, 

61 LEIntEnumField, 

62 LEIntField, 

63 LELongField, 

64 LEShortEnumField, 

65 LEShortField, 

66 LenField, 

67 MultipleTypeField, 

68 PacketField, 

69 PacketLenField, 

70 PacketListField, 

71 PadField, 

72 ReversePadField, 

73 ShortEnumField, 

74 ShortField, 

75 SignedByteField, 

76 StrField, 

77 StrFixedLenField, 

78 StrLenField, 

79 StrLenFieldUtf16, 

80 StrNullField, 

81 StrNullFieldUtf16, 

82 TrailerField, 

83 UUIDEnumField, 

84 UUIDField, 

85 XByteField, 

86 XLEIntField, 

87 XLELongField, 

88 XLEShortField, 

89 XShortField, 

90 XStrFixedLenField, 

91) 

92from scapy.sessions import DefaultSession 

93from scapy.supersocket import StreamSocket 

94 

95from scapy.layers.kerberos import ( 

96 KRB_InnerToken, 

97 Kerberos, 

98) 

99from scapy.layers.gssapi import ( 

100 GSS_S_COMPLETE, 

101 GSSAPI_BLOB_SIGNATURE, 

102 GSSAPI_BLOB, 

103 SSP, 

104) 

105from scapy.layers.inet import TCP 

106 

107from scapy.contrib.rtps.common_types import ( 

108 EField, 

109 EPacket, 

110 EPacketField, 

111 EPacketListField, 

112) 

113 

114# Typing imports 

115from typing import ( 

116 Optional, 

117) 

118 

119# the alignment of auth_pad 

120# This is 4 in [C706] 13.2.6.1 but was updated to 16 in [MS-RPCE] 2.2.2.11 

121_COMMON_AUTH_PAD = 16 

122# the alignment of the NDR Type 1 serialization private header 

123# ([MS-RPCE] sect 2.2.6.2) 

124_TYPE1_S_PAD = 8 

125 

126# DCE/RPC Packet 

127DCE_RPC_TYPE = { 

128 0: "request", 

129 1: "ping", 

130 2: "response", 

131 3: "fault", 

132 4: "working", 

133 5: "no_call", 

134 6: "reject", 

135 7: "acknowledge", 

136 8: "connectionless_cancel", 

137 9: "frag_ack", 

138 10: "cancel_ack", 

139 11: "bind", 

140 12: "bind_ack", 

141 13: "bind_nak", 

142 14: "alter_context", 

143 15: "alter_context_resp", 

144 16: "auth3", 

145 17: "shutdown", 

146 18: "co_cancel", 

147 19: "orphaned", 

148} 

149_DCE_RPC_4_FLAGS1 = [ 

150 "reserved_01", 

151 "last_frag", 

152 "frag", 

153 "no_frag_ack", 

154 "maybe", 

155 "idempotent", 

156 "broadcast", 

157 "reserved_7", 

158] 

159_DCE_RPC_4_FLAGS2 = [ 

160 "reserved_0", 

161 "cancel_pending", 

162 "reserved_2", 

163 "reserved_3", 

164 "reserved_4", 

165 "reserved_5", 

166 "reserved_6", 

167 "reserved_7", 

168] 

169DCE_RPC_TRANSFER_SYNTAXES = { 

170 UUID("00000000-0000-0000-0000-000000000000"): "NULL", 

171 UUID("6cb71c2c-9812-4540-0300-000000000000"): "Bind Time Feature Negotiation", 

172 UUID("8a885d04-1ceb-11c9-9fe8-08002b104860"): "NDR 2.0", 

173 UUID("71710533-beba-4937-8319-b5dbef9ccc36"): "NDR64", 

174} 

175DCE_RPC_INTERFACES_NAMES = {} 

176DCE_RPC_INTERFACES_NAMES_rev = {} 

177 

178 

179class DCERPC_Transport(IntEnum): 

180 NCACN_IP_TCP = 1 

181 NCACN_NP = 2 

182 # TODO: add more.. if people use them? 

183 

184 

185def _dce_rpc_endianness(pkt): 

186 """ 

187 Determine the right endianness sign for a given DCE/RPC packet 

188 """ 

189 if pkt.endian == 0: # big endian 

190 return ">" 

191 elif pkt.endian == 1: # little endian 

192 return "<" 

193 else: 

194 return "!" 

195 

196 

197class _EField(EField): 

198 def __init__(self, fld): 

199 super(_EField, self).__init__(fld, endianness_from=_dce_rpc_endianness) 

200 

201 

202class DceRpc(Packet): 

203 """DCE/RPC packet""" 

204 

205 @classmethod 

206 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

207 if _pkt and len(_pkt) >= 1: 

208 ver = ord(_pkt[0:1]) 

209 if ver == 4: 

210 return DceRpc4 

211 elif ver == 5: 

212 return DceRpc5 

213 return DceRpc5 

214 

215 

216bind_bottom_up(TCP, DceRpc, sport=135) 

217bind_layers(TCP, DceRpc, dport=135) 

218 

219 

220class _DceRpcPayload(Packet): 

221 @property 

222 def endianness(self): 

223 if not self.underlayer: 

224 return "!" 

225 return _dce_rpc_endianness(self.underlayer) 

226 

227 

228# sect 12.5 

229 

230_drep = [ 

231 BitEnumField("endian", 1, 4, ["big", "little"]), 

232 BitEnumField("encoding", 0, 4, ["ASCII", "EBCDIC"]), 

233 ByteEnumField("float", 0, ["IEEE", "VAX", "CRAY", "IBM"]), 

234 ByteField("reserved1", 0), 

235] 

236 

237 

238class DceRpc4(DceRpc): 

239 """ 

240 DCE/RPC v4 'connection-less' packet 

241 """ 

242 

243 name = "DCE/RPC v4" 

244 fields_desc = ( 

245 [ 

246 ByteEnumField( 

247 "rpc_vers", 4, {4: "4 (connection-less)", 5: "5 (connection-oriented)"} 

248 ), 

249 ByteEnumField("ptype", 0, DCE_RPC_TYPE), 

250 FlagsField("flags1", 0, 8, _DCE_RPC_4_FLAGS1), 

251 FlagsField("flags2", 0, 8, _DCE_RPC_4_FLAGS2), 

252 ] 

253 + _drep 

254 + [ 

255 XByteField("serial_hi", 0), 

256 _EField(UUIDField("object", None)), 

257 _EField(UUIDField("if_id", None)), 

258 _EField(UUIDField("act_id", None)), 

259 _EField(IntField("server_boot", 0)), 

260 _EField(IntField("if_vers", 1)), 

261 _EField(IntField("seqnum", 0)), 

262 _EField(ShortField("opnum", 0)), 

263 _EField(XShortField("ihint", 0xFFFF)), 

264 _EField(XShortField("ahint", 0xFFFF)), 

265 _EField(LenField("len", None, fmt="H")), 

266 _EField(ShortField("fragnum", 0)), 

267 ByteEnumField("auth_proto", 0, ["none", "OSF DCE Private Key"]), 

268 XByteField("serial_lo", 0), 

269 ] 

270 ) 

271 

272 

273# Exceptionally, we define those 3 here. 

274 

275 

276class NL_AUTH_MESSAGE(Packet): 

277 # [MS-NRPC] sect 2.2.1.3.1 

278 name = "NL_AUTH_MESSAGE" 

279 fields_desc = [ 

280 LEIntEnumField( 

281 "MessageType", 

282 0x00000000, 

283 { 

284 0x00000000: "Request", 

285 0x00000001: "Response", 

286 }, 

287 ), 

288 FlagsField( 

289 "Flags", 

290 0, 

291 -32, 

292 [ 

293 "NETBIOS_DOMAIN_NAME", 

294 "NETBIOS_COMPUTER_NAME", 

295 "DNS_DOMAIN_NAME", 

296 "DNS_HOST_NAME", 

297 "NETBIOS_COMPUTER_NAME_UTF8", 

298 ], 

299 ), 

300 ConditionalField( 

301 StrNullField("NetbiosDomainName", ""), 

302 lambda pkt: pkt.Flags.NETBIOS_DOMAIN_NAME, 

303 ), 

304 ConditionalField( 

305 StrNullField("NetbiosComputerName", ""), 

306 lambda pkt: pkt.Flags.NETBIOS_COMPUTER_NAME, 

307 ), 

308 ConditionalField( 

309 DNSStrField("DnsDomainName", ""), 

310 lambda pkt: pkt.Flags.DNS_DOMAIN_NAME, 

311 ), 

312 ConditionalField( 

313 DNSStrField("DnsHostName", ""), 

314 lambda pkt: pkt.Flags.DNS_HOST_NAME, 

315 ), 

316 ConditionalField( 

317 # What the fuck? Why are they doing this 

318 # The spec is just wrong 

319 DNSStrField("NetbiosComputerNameUtf8", ""), 

320 lambda pkt: pkt.Flags.NETBIOS_COMPUTER_NAME_UTF8, 

321 ), 

322 ] 

323 

324 

325class NL_AUTH_SIGNATURE(Packet): 

326 # [MS-NRPC] sect 2.2.1.3.2/2.2.1.3.3 

327 name = "NL_AUTH_(SHA2_)SIGNATURE" 

328 fields_desc = [ 

329 LEShortEnumField( 

330 "SignatureAlgorithm", 

331 0x0077, 

332 { 

333 0x0077: "HMAC-MD5", 

334 0x0013: "HMAC-SHA256", 

335 }, 

336 ), 

337 LEShortEnumField( 

338 "SealAlgorithm", 

339 0xFFFF, 

340 { 

341 0xFFFF: "Unencrypted", 

342 0x007A: "RC4", 

343 0x001A: "AES-128", 

344 }, 

345 ), 

346 XLEShortField("Pad", 0xFFFF), 

347 ShortField("Flags", 0), 

348 XStrFixedLenField("SequenceNumber", b"", length=8), 

349 XStrFixedLenField("Checksum", b"", length=8), 

350 ConditionalField( 

351 XStrFixedLenField("Confounder", b"", length=8), 

352 lambda pkt: pkt.SealAlgorithm != 0xFFFF, 

353 ), 

354 MultipleTypeField( 

355 [ 

356 ( 

357 StrFixedLenField("Reserved2", b"", length=24), 

358 lambda pkt: pkt.SignatureAlgorithm == 0x0013, 

359 ), 

360 ], 

361 StrField("Reserved2", b""), 

362 ), 

363 ] 

364 

365 

366# [MS-RPCE] sect 2.2.1.1.7 

367# https://learn.microsoft.com/en-us/windows/win32/rpc/authentication-service-constants 

368# rpcdce.h 

369 

370 

371class RPC_C_AUTHN(IntEnum): 

372 NONE = 0x00 

373 DCE_PRIVATE = 0x01 

374 DCE_PUBLIC = 0x02 

375 DEC_PUBLIC = 0x04 

376 GSS_NEGOTIATE = 0x09 

377 WINNT = 0x0A 

378 GSS_SCHANNEL = 0x0E 

379 GSS_KERBEROS = 0x10 

380 DPA = 0x11 

381 MSN = 0x12 

382 KERNEL = 0x14 

383 DIGEST = 0x15 

384 NEGO_EXTENDED = 0x1E 

385 PKU2U = 0x1F 

386 LIVE_SSP = 0x20 

387 LIVEXP_SSP = 0x23 

388 CLOUD_AP = 0x24 

389 NETLOGON = 0x44 

390 MSONLINE = 0x52 

391 MQ = 0x64 

392 DEFAULT = 0xFFFFFFFF 

393 

394 

395class RPC_C_AUTHN_LEVEL(IntEnum): 

396 DEFAULT = 0x0 

397 NONE = 0x1 

398 CONNECT = 0x2 

399 CALL = 0x3 

400 PKT = 0x4 

401 PKT_INTEGRITY = 0x5 

402 PKT_PRIVACY = 0x6 

403 

404 

405DCE_C_AUTHN_LEVEL = RPC_C_AUTHN_LEVEL # C706 name 

406 

407 

408# C706 sect 13.2.6.1 

409 

410 

411class CommonAuthVerifier(Packet): 

412 name = "Common Authentication Verifier" 

413 fields_desc = [ 

414 ByteEnumField( 

415 "auth_type", 

416 0, 

417 RPC_C_AUTHN, 

418 ), 

419 ByteEnumField("auth_level", 0, RPC_C_AUTHN_LEVEL), 

420 ByteField("auth_pad_length", None), 

421 ByteField("auth_reserved", 0), 

422 XLEIntField("auth_context_id", 0), 

423 MultipleTypeField( 

424 [ 

425 # SPNEGO 

426 ( 

427 PacketLenField( 

428 "auth_value", 

429 GSSAPI_BLOB(), 

430 GSSAPI_BLOB, 

431 length_from=lambda pkt: pkt.parent.auth_len, 

432 ), 

433 lambda pkt: pkt.auth_type == 0x09 and pkt.parent and 

434 # Bind/Alter 

435 pkt.parent.ptype in [11, 12, 13, 14, 15, 16], 

436 ), 

437 ( 

438 PacketLenField( 

439 "auth_value", 

440 GSSAPI_BLOB_SIGNATURE(), 

441 GSSAPI_BLOB_SIGNATURE, 

442 length_from=lambda pkt: pkt.parent.auth_len, 

443 ), 

444 lambda pkt: pkt.auth_type == 0x09 

445 and pkt.parent 

446 and ( 

447 # Other 

448 not pkt.parent 

449 or pkt.parent.ptype not in [11, 12, 13, 14, 15, 16] 

450 ), 

451 ), 

452 # Kerberos 

453 ( 

454 PacketLenField( 

455 "auth_value", 

456 Kerberos(), 

457 Kerberos, 

458 length_from=lambda pkt: pkt.parent.auth_len, 

459 ), 

460 lambda pkt: pkt.auth_type == 0x10 and pkt.parent and 

461 # Bind/Alter 

462 pkt.parent.ptype in [11, 12, 13, 14, 15, 16], 

463 ), 

464 ( 

465 PacketLenField( 

466 "auth_value", 

467 KRB_InnerToken(), 

468 KRB_InnerToken, 

469 length_from=lambda pkt: pkt.parent.auth_len, 

470 ), 

471 lambda pkt: pkt.auth_type == 0x10 

472 and pkt.parent 

473 and ( 

474 # Other 

475 not pkt.parent 

476 or pkt.parent.ptype not in [11, 12, 13, 14, 15, 16] 

477 ), 

478 ), 

479 # NTLM 

480 ( 

481 PacketLenField( 

482 "auth_value", 

483 NTLM_Header(), 

484 NTLM_Header, 

485 length_from=lambda pkt: pkt.parent.auth_len, 

486 ), 

487 lambda pkt: pkt.auth_type in [0x0A, 0xFF] and pkt.parent and 

488 # Bind/Alter 

489 pkt.parent.ptype in [11, 12, 13, 14, 15, 16], 

490 ), 

491 ( 

492 PacketLenField( 

493 "auth_value", 

494 NTLMSSP_MESSAGE_SIGNATURE(), 

495 NTLMSSP_MESSAGE_SIGNATURE, 

496 length_from=lambda pkt: pkt.parent.auth_len, 

497 ), 

498 lambda pkt: pkt.auth_type in [0x0A, 0xFF] 

499 and pkt.parent 

500 and ( 

501 # Other 

502 not pkt.parent 

503 or pkt.parent.ptype not in [11, 12, 13, 14, 15, 16] 

504 ), 

505 ), 

506 # NetLogon 

507 ( 

508 PacketLenField( 

509 "auth_value", 

510 NL_AUTH_MESSAGE(), 

511 NL_AUTH_MESSAGE, 

512 length_from=lambda pkt: pkt.parent.auth_len, 

513 ), 

514 lambda pkt: pkt.auth_type == 0x44 and pkt.parent and 

515 # Bind/Alter 

516 pkt.parent.ptype in [11, 12, 13, 14, 15], 

517 ), 

518 ( 

519 PacketLenField( 

520 "auth_value", 

521 NL_AUTH_SIGNATURE(), 

522 NL_AUTH_SIGNATURE, 

523 length_from=lambda pkt: pkt.parent.auth_len, 

524 ), 

525 lambda pkt: pkt.auth_type == 0x44 

526 and ( 

527 # Other 

528 not pkt.parent 

529 or pkt.parent.ptype not in [11, 12, 13, 14, 15] 

530 ), 

531 ), 

532 ], 

533 PacketLenField( 

534 "auth_value", 

535 None, 

536 conf.raw_layer, 

537 length_from=lambda pkt: pkt.parent and pkt.parent.auth_len or 0, 

538 ), 

539 ), 

540 ] 

541 

542 def is_protected(self): 

543 if not self.auth_value: 

544 return False 

545 if self.parent and self.parent.ptype in [11, 12, 13, 14, 15, 16]: 

546 return False 

547 return True 

548 

549 def is_ssp(self): 

550 if not self.auth_value: 

551 return False 

552 if self.parent and self.parent.ptype not in [11, 12, 13, 14, 15, 16]: 

553 return False 

554 return True 

555 

556 def default_payload_class(self, pkt): 

557 return conf.padding_layer 

558 

559 

560# [MS-RPCE] sect 2.2.2.13 - Verification Trailer 

561_SECTRAILER_MAGIC = b"\x8a\xe3\x13\x71\x02\xf4\x36\x71" 

562 

563 

564class DceRpcSecVTCommand(Packet): 

565 name = "Verification trailer command" 

566 fields_desc = [ 

567 BitField("SEC_VT_MUST_PROCESS_COMMAND", 0, 1, tot_size=-2), 

568 BitField("SEC_VT_COMMAND_END", 0, 1), 

569 BitEnumField( 

570 "Command", 

571 0, 

572 -14, 

573 { 

574 0x0001: "SEC_VT_COMMAND_BITMASK_1", 

575 0x0002: "SEC_VT_COMMAND_PCONTEXT", 

576 0x0003: "SEC_VT_COMMAND_HEADER2", 

577 }, 

578 end_tot_size=-2, 

579 ), 

580 LEShortField("Length", None), 

581 ] 

582 

583 def guess_payload_class(self, payload): 

584 if self.Command == 0x0001: 

585 return DceRpcSecVTBitmask 

586 elif self.Command == 0x0002: 

587 return DceRpcSecVTPcontext 

588 elif self.Command == 0x0003: 

589 return DceRpcSecVTHeader2 

590 return conf.raw_payload 

591 

592 

593# [MS-RPCE] sect 2.2.2.13.2 

594 

595 

596class DceRpcSecVTBitmask(Packet): 

597 name = "rpc_sec_vt_bitmask" 

598 fields_desc = [ 

599 LEIntField("bits", 1), 

600 ] 

601 

602 def default_payload_class(self, pkt): 

603 return conf.padding_layer 

604 

605 

606# [MS-RPCE] sect 2.2.2.13.4 

607 

608 

609class DceRpcSecVTPcontext(Packet): 

610 name = "rpc_sec_vt_pcontext" 

611 fields_desc = [ 

612 UUIDEnumField( 

613 "InterfaceId", 

614 None, 

615 ( 

616 DCE_RPC_INTERFACES_NAMES.get, 

617 lambda x: DCE_RPC_INTERFACES_NAMES_rev.get(x.lower()), 

618 ), 

619 uuid_fmt=UUIDField.FORMAT_LE, 

620 ), 

621 LEIntField("Version", 0), 

622 UUIDEnumField( 

623 "TransferSyntax", 

624 None, 

625 DCE_RPC_TRANSFER_SYNTAXES, 

626 uuid_fmt=UUIDField.FORMAT_LE, 

627 ), 

628 LEIntField("TransferVersion", 0), 

629 ] 

630 

631 def default_payload_class(self, pkt): 

632 return conf.padding_layer 

633 

634 

635# [MS-RPCE] sect 2.2.2.13.3 

636 

637 

638class DceRpcSecVTHeader2(Packet): 

639 name = "rpc_sec_vt_header2" 

640 fields_desc = [ 

641 ByteField("PTYPE", 0), 

642 ByteField("Reserved1", 0), 

643 LEShortField("Reserved2", 0), 

644 LEIntField("drep", 0), 

645 LEIntField("call_id", 0), 

646 LEShortField("p_cont_id", 0), 

647 LEShortField("opnum", 0), 

648 ] 

649 

650 def default_payload_class(self, pkt): 

651 return conf.padding_layer 

652 

653 

654class DceRpcSecVT(Packet): 

655 name = "Verification trailer" 

656 fields_desc = [ 

657 XStrFixedLenField("rpc_sec_verification_trailer", _SECTRAILER_MAGIC, length=8), 

658 PacketListField("commands", [], DceRpcSecVTCommand), 

659 ] 

660 

661 

662class _VerifTrailerField(PacketField): 

663 def getfield( 

664 self, 

665 pkt, 

666 s, 

667 ): 

668 if _SECTRAILER_MAGIC in s: 

669 # a bit ugly 

670 ind = s.index(_SECTRAILER_MAGIC) 

671 sectrailer_bytes, remain = bytes(s[:-ind]), bytes(s[-ind:]) 

672 vt_trailer = self.m2i(pkt, sectrailer_bytes) 

673 if not isinstance(vt_trailer.payload, NoPayload): 

674 # bad parse 

675 return s, None 

676 return remain, vt_trailer 

677 return s, None 

678 

679 

680# sect 12.6.3 

681 

682 

683_DCE_RPC_5_FLAGS = { 

684 0x01: "PFC_FIRST_FRAG", 

685 0x02: "PFC_LAST_FRAG", 

686 0x04: "PFC_PENDING_CANCEL", 

687 0x08: "PFC_RESERVED_1", 

688 0x10: "PFC_CONC_MPX", 

689 0x20: "PFC_DID_NOT_EXECUTE", 

690 0x40: "PFC_MAYBE", 

691 0x80: "PFC_OBJECT_UUID", 

692} 

693 

694# [MS-RPCE] sect 2.2.2.3 

695 

696_DCE_RPC_5_FLAGS_2 = _DCE_RPC_5_FLAGS.copy() 

697_DCE_RPC_5_FLAGS_2[0x04] = "PFC_SUPPORT_HEADER_SIGN" 

698 

699 

700_DCE_RPC_ERROR_CODES = { 

701 # Appendix N 

702 0x1C010001: "nca_s_comm_failure", 

703 0x1C010002: "nca_s_op_rng_error", 

704 0x1C010003: "nca_s_unk_if", 

705 0x1C010006: "nca_s_wrong_boot_time", 

706 0x1C010009: "nca_s_you_crashed", 

707 0x1C01000B: "nca_s_proto_error", 

708 0x1C010013: "nca_s_out_args_too_big", 

709 0x1C010014: "nca_s_server_too_busy", 

710 0x1C010015: "nca_s_fault_string_too_long", 

711 0x1C010017: "nca_s_unsupported_type", 

712 0x1C000001: "nca_s_fault_int_div_by_zero", 

713 0x1C000002: "nca_s_fault_addr_error", 

714 0x1C000003: "nca_s_fault_fp_div_zero", 

715 0x1C000004: "nca_s_fault_fp_underflow", 

716 0x1C000005: "nca_s_fault_fp_overflow", 

717 0x1C000006: "nca_s_fault_invalid_tag", 

718 0x1C000007: "nca_s_fault_invalid_bound", 

719 0x1C000008: "nca_s_rpc_version_mismatch", 

720 0x1C000009: "nca_s_unspec_reject", 

721 0x1C00000A: "nca_s_bad_actid", 

722 0x1C00000B: "nca_s_who_are_you_failed", 

723 0x1C00000C: "nca_s_manager_not_entered", 

724 0x1C00000D: "nca_s_fault_cancel", 

725 0x1C00000E: "nca_s_fault_ill_inst", 

726 0x1C00000F: "nca_s_fault_fp_error", 

727 0x1C000010: "nca_s_fault_int_overflow", 

728 0x1C000012: "nca_s_fault_unspec", 

729 0x1C000013: "nca_s_fault_remote_comm_failure", 

730 0x1C000014: "nca_s_fault_pipe_empty", 

731 0x1C000015: "nca_s_fault_pipe_closed", 

732 0x1C000016: "nca_s_fault_pipe_order", 

733 0x1C000017: "nca_s_fault_pipe_discipline", 

734 0x1C000018: "nca_s_fault_pipe_comm_error", 

735 0x1C000019: "nca_s_fault_pipe_memory", 

736 0x1C00001A: "nca_s_fault_context_mismatch", 

737 0x1C00001B: "nca_s_fault_remote_no_memory", 

738 0x1C00001C: "nca_s_invalid_pres_context_id", 

739 0x1C00001D: "nca_s_unsupported_authn_level", 

740 0x1C00001F: "nca_s_invalid_checksum", 

741 0x1C000020: "nca_s_invalid_crc", 

742 0x1C000021: "nca_s_fault_user_defined", 

743 0x1C000022: "nca_s_fault_tx_open_failed", 

744 0x1C000023: "nca_s_fault_codeset_conv_error", 

745 0x1C000024: "nca_s_fault_object_not_found", 

746 0x1C000025: "nca_s_fault_no_client_stub", 

747 # [MS-ERREF] 

748 0x000006D3: "RPC_S_UNKNOWN_AUTHN_SERVICE", 

749 0x000006F7: "RPC_X_BAD_STUB_DATA", 

750 # [MS-RPCE] 

751 0x000006D8: "EPT_S_CANT_PERFORM_OP", 

752} 

753 

754_DCE_RPC_REJECTION_REASONS = { 

755 0: "REASON_NOT_SPECIFIED", 

756 1: "TEMPORARY_CONGESTION", 

757 2: "LOCAL_LIMIT_EXCEEDED", 

758 3: "CALLED_PADDR_UNKNOWN", 

759 4: "PROTOCOL_VERSION_NOT_SUPPORTED", 

760 5: "DEFAULT_CONTEXT_NOT_SUPPORTED", 

761 6: "USER_DATA_NOT_READABLE", 

762 7: "NO_PSAP_AVAILABLE", 

763 8: "AUTHENTICATION_TYPE_NOT_RECOGNIZED", 

764 9: "INVALID_CHECKSUM", 

765} 

766 

767 

768class DceRpc5(DceRpc): 

769 """ 

770 DCE/RPC v5 'connection-oriented' packet 

771 """ 

772 

773 name = "DCE/RPC v5" 

774 fields_desc = ( 

775 [ 

776 ByteEnumField( 

777 "rpc_vers", 5, {4: "4 (connection-less)", 5: "5 (connection-oriented)"} 

778 ), 

779 ByteField("rpc_vers_minor", 0), 

780 ByteEnumField("ptype", 0, DCE_RPC_TYPE), 

781 MultipleTypeField( 

782 # [MS-RPCE] sect 2.2.2.3 

783 [ 

784 ( 

785 FlagsField("pfc_flags", 0x3, 8, _DCE_RPC_5_FLAGS_2), 

786 lambda pkt: pkt.ptype in [11, 12, 13, 14, 15, 16], 

787 ) 

788 ], 

789 FlagsField("pfc_flags", 0x3, 8, _DCE_RPC_5_FLAGS), 

790 ), 

791 ] 

792 + _drep 

793 + [ 

794 ByteField("reserved2", 0), 

795 _EField(ShortField("frag_len", None)), 

796 _EField( 

797 FieldLenField( 

798 "auth_len", 

799 None, 

800 fmt="H", 

801 length_of="auth_verifier", 

802 adjust=lambda pkt, x: 0 if not x else (x - 8), 

803 ) 

804 ), 

805 _EField(IntField("call_id", None)), 

806 # Now let's proceed with trailer fields, i.e. at the end of the PACKET 

807 # (below all payloads, etc.). Have a look at Figure 3 in sect 2.2.2.13 

808 # of [MS-RPCE] but note the following: 

809 # - auth_verifier includes sec_trailer + the authentication token 

810 # - auth_padding is the authentication padding 

811 # - vt_trailer is the verification trailer 

812 ConditionalField( 

813 TrailerField( 

814 PacketLenField( 

815 "auth_verifier", 

816 None, 

817 CommonAuthVerifier, 

818 length_from=lambda pkt: pkt.auth_len + 8, 

819 ) 

820 ), 

821 lambda pkt: pkt.auth_len != 0, 

822 ), 

823 ConditionalField( 

824 TrailerField( 

825 StrLenField( 

826 "auth_padding", 

827 None, 

828 length_from=lambda pkt: pkt.auth_verifier.auth_pad_length, 

829 ) 

830 ), 

831 lambda pkt: pkt.auth_len != 0, 

832 ), 

833 TrailerField( 

834 _VerifTrailerField("vt_trailer", None, DceRpcSecVT), 

835 ), 

836 ] 

837 ) 

838 

839 def do_dissect(self, s): 

840 # Overload do_dissect to only include the current layer in dissection. 

841 # This allows to support TrailerFields, even in the case where multiple DceRpc5 

842 # packets are concatenated 

843 frag_len = self.get_field("frag_len").getfield(self, s[8:10])[1] 

844 s, remain = s[:frag_len], s[frag_len:] 

845 return super(DceRpc5, self).do_dissect(s) + remain 

846 

847 def extract_padding(self, s): 

848 # Now, take any data that doesn't fit in the current fragment and make it 

849 # padding. The caller is responsible for looking for eventual padding and 

850 # creating the next fragment, etc. 

851 pay_len = self.frag_len - len(self.original) + len(s) 

852 return s[:pay_len], s[pay_len:] 

853 

854 def post_build(self, pkt, pay): 

855 if ( 

856 self.auth_verifier 

857 and self.auth_padding is None 

858 and self.auth_verifier.auth_pad_length is None 

859 ): 

860 # Compute auth_len and add padding 

861 auth_len = self.get_field("auth_len").getfield(self, pkt[10:12])[1] + 8 

862 auth_verifier, pay = pay[-auth_len:], pay[:-auth_len] 

863 pdu_len = len(pay) 

864 if self.payload: 

865 pdu_len -= len(self.payload.self_build()) 

866 padlen = (-pdu_len) % _COMMON_AUTH_PAD 

867 auth_verifier = ( 

868 auth_verifier[:2] + struct.pack("B", padlen) + auth_verifier[3:] 

869 ) 

870 pay = pay + (padlen * b"\x00") + auth_verifier 

871 if self.frag_len is None: 

872 # Compute frag_len 

873 length = len(pkt) + len(pay) 

874 pkt = ( 

875 pkt[:8] 

876 + self.get_field("frag_len").addfield(self, b"", length) 

877 + pkt[10:] 

878 ) 

879 return pkt + pay 

880 

881 def answers(self, pkt): 

882 return isinstance(pkt, DceRpc5) and pkt[DceRpc5].call_id == self.call_id 

883 

884 @classmethod 

885 def tcp_reassemble(cls, data, _, session): 

886 if data[0:1] != b"\x05": 

887 return 

888 endian = struct.unpack("!B", data[4:5])[0] >> 4 

889 if endian not in [0, 1]: 

890 return 

891 length = struct.unpack(("<" if endian else ">") + "H", data[8:10])[0] 

892 if len(data) >= length: 

893 if conf.dcerpc_session_enable: 

894 # If DCE/RPC sessions are enabled, use them ! 

895 if "dcerpcsess" not in session: 

896 session["dcerpcsess"] = dcerpcsess = DceRpcSession() 

897 else: 

898 dcerpcsess = session["dcerpcsess"] 

899 return dcerpcsess.process(DceRpc5(data)) 

900 return DceRpc5(data) 

901 

902 

903# sec 12.6.3.1 

904 

905 

906class DceRpc5AbstractSyntax(EPacket): 

907 name = "Presentation Syntax (p_syntax_id_t)" 

908 fields_desc = [ 

909 _EField( 

910 UUIDEnumField( 

911 "if_uuid", 

912 None, 

913 ( 

914 # Those are dynamic 

915 DCE_RPC_INTERFACES_NAMES.get, 

916 lambda x: DCE_RPC_INTERFACES_NAMES_rev.get(x.lower()), 

917 ), 

918 ) 

919 ), 

920 _EField(IntField("if_version", 3)), 

921 ] 

922 

923 

924class DceRpc5TransferSyntax(EPacket): 

925 name = "Presentation Transfer Syntax (p_syntax_id_t)" 

926 fields_desc = [ 

927 _EField( 

928 UUIDEnumField( 

929 "if_uuid", 

930 None, 

931 DCE_RPC_TRANSFER_SYNTAXES, 

932 ) 

933 ), 

934 _EField(IntField("if_version", 3)), 

935 ] 

936 

937 

938class DceRpc5Context(EPacket): 

939 name = "Presentation Context (p_cont_elem_t)" 

940 fields_desc = [ 

941 _EField(ShortField("cont_id", 0)), 

942 FieldLenField("n_transfer_syn", None, count_of="transfer_syntaxes", fmt="B"), 

943 ByteField("reserved", 0), 

944 EPacketField("abstract_syntax", None, DceRpc5AbstractSyntax), 

945 EPacketListField( 

946 "transfer_syntaxes", 

947 None, 

948 DceRpc5TransferSyntax, 

949 count_from=lambda pkt: pkt.n_transfer_syn, 

950 endianness_from=_dce_rpc_endianness, 

951 ), 

952 ] 

953 

954 

955class DceRpc5Result(EPacket): 

956 name = "Context negotiation Result" 

957 fields_desc = [ 

958 _EField( 

959 ShortEnumField( 

960 "result", 0, ["acceptance", "user_rejection", "provider_rejection"] 

961 ) 

962 ), 

963 _EField( 

964 ShortEnumField( 

965 "reason", 

966 0, 

967 _DCE_RPC_REJECTION_REASONS, 

968 ) 

969 ), 

970 EPacketField("transfer_syntax", None, DceRpc5TransferSyntax), 

971 ] 

972 

973 

974class DceRpc5PortAny(EPacket): 

975 name = "Port Any (port_any_t)" 

976 fields_desc = [ 

977 _EField(FieldLenField("length", None, length_of="port_spec", fmt="H")), 

978 _EField(StrLenField("port_spec", b"", length_from=lambda pkt: pkt.length)), 

979 ] 

980 

981 

982# sec 12.6.4.3 

983 

984 

985class DceRpc5Bind(_DceRpcPayload): 

986 name = "DCE/RPC v5 - Bind" 

987 fields_desc = [ 

988 _EField(ShortField("max_xmit_frag", 5840)), 

989 _EField(ShortField("max_recv_frag", 8192)), 

990 _EField(IntField("assoc_group_id", 0)), 

991 # p_cont_list_t 

992 _EField( 

993 FieldLenField("n_context_elem", None, count_of="context_elem", fmt="B") 

994 ), 

995 StrFixedLenField("reserved", 0, length=3), 

996 EPacketListField( 

997 "context_elem", 

998 [], 

999 DceRpc5Context, 

1000 endianness_from=_dce_rpc_endianness, 

1001 count_from=lambda pkt: pkt.n_context_elem, 

1002 ), 

1003 ] 

1004 

1005 

1006bind_layers(DceRpc5, DceRpc5Bind, ptype=11) 

1007 

1008# sec 12.6.4.4 

1009 

1010 

1011class DceRpc5BindAck(_DceRpcPayload): 

1012 name = "DCE/RPC v5 - Bind Ack" 

1013 fields_desc = [ 

1014 _EField(ShortField("max_xmit_frag", 5840)), 

1015 _EField(ShortField("max_recv_frag", 8192)), 

1016 _EField(IntField("assoc_group_id", 0)), 

1017 PadField( 

1018 EPacketField("sec_addr", None, DceRpc5PortAny), 

1019 align=4, 

1020 ), 

1021 # p_result_list_t 

1022 _EField(FieldLenField("n_results", None, count_of="results", fmt="B")), 

1023 StrFixedLenField("reserved", 0, length=3), 

1024 EPacketListField( 

1025 "results", 

1026 [], 

1027 DceRpc5Result, 

1028 endianness_from=_dce_rpc_endianness, 

1029 count_from=lambda pkt: pkt.n_results, 

1030 ), 

1031 ] 

1032 

1033 

1034bind_layers(DceRpc5, DceRpc5BindAck, ptype=12) 

1035 

1036# sec 12.6.4.5 

1037 

1038 

1039class DceRpc5Version(EPacket): 

1040 name = "version_t" 

1041 fields_desc = [ 

1042 ByteField("major", 0), 

1043 ByteField("minor", 0), 

1044 ] 

1045 

1046 

1047class DceRpc5BindNak(_DceRpcPayload): 

1048 name = "DCE/RPC v5 - Bind Nak" 

1049 fields_desc = [ 

1050 _EField( 

1051 ShortEnumField("provider_reject_reason", 0, _DCE_RPC_REJECTION_REASONS) 

1052 ), 

1053 # p_rt_versions_supported_t 

1054 _EField(FieldLenField("n_protocols", None, count_of="protocols", fmt="B")), 

1055 EPacketListField( 

1056 "protocols", 

1057 [], 

1058 DceRpc5Version, 

1059 count_from=lambda pkt: pkt.n_protocols, 

1060 endianness_from=_dce_rpc_endianness, 

1061 ), 

1062 # [MS-RPCE] sect 2.2.2.9 

1063 ConditionalField( 

1064 ReversePadField( 

1065 _EField( 

1066 UUIDEnumField( 

1067 "signature", 

1068 None, 

1069 { 

1070 UUID( 

1071 "90740320-fad0-11d3-82d7-009027b130ab" 

1072 ): "Extended Error", 

1073 }, 

1074 ) 

1075 ), 

1076 align=8, 

1077 ), 

1078 lambda pkt: pkt.fields.get("signature", None) 

1079 or ( 

1080 pkt.underlayer 

1081 and pkt.underlayer.frag_len >= 24 + pkt.n_protocols * 2 + 16 

1082 ), 

1083 ), 

1084 ] 

1085 

1086 

1087bind_layers(DceRpc5, DceRpc5BindNak, ptype=13) 

1088 

1089 

1090# sec 12.6.4.1 

1091 

1092 

1093class DceRpc5AlterContext(_DceRpcPayload): 

1094 name = "DCE/RPC v5 - AlterContext" 

1095 fields_desc = DceRpc5Bind.fields_desc 

1096 

1097 

1098bind_layers(DceRpc5, DceRpc5AlterContext, ptype=14) 

1099 

1100 

1101# sec 12.6.4.2 

1102 

1103 

1104class DceRpc5AlterContextResp(_DceRpcPayload): 

1105 name = "DCE/RPC v5 - AlterContextResp" 

1106 fields_desc = DceRpc5BindAck.fields_desc 

1107 

1108 

1109bind_layers(DceRpc5, DceRpc5AlterContextResp, ptype=15) 

1110 

1111# [MS-RPCE] sect 2.2.2.10 - rpc_auth_3 

1112 

1113 

1114class DceRpc5Auth3(Packet): 

1115 name = "DCE/RPC v5 - Auth3" 

1116 fields_desc = [StrFixedLenField("pad", b"", length=4)] 

1117 

1118 

1119bind_layers(DceRpc5, DceRpc5Auth3, ptype=16) 

1120 

1121# sec 12.6.4.7 

1122 

1123 

1124class DceRpc5Fault(_DceRpcPayload): 

1125 name = "DCE/RPC v5 - Fault" 

1126 fields_desc = [ 

1127 _EField(IntField("alloc_hint", 0)), 

1128 _EField(ShortField("cont_id", 0)), 

1129 ByteField("cancel_count", 0), 

1130 FlagsField("reserved", 0, -8, {0x1: "RPC extended error"}), 

1131 _EField(LEIntEnumField("status", 0, _DCE_RPC_ERROR_CODES)), 

1132 IntField("reserved2", 0), 

1133 ] 

1134 

1135 

1136bind_layers(DceRpc5, DceRpc5Fault, ptype=3) 

1137 

1138 

1139# sec 12.6.4.9 

1140 

1141 

1142class DceRpc5Request(_DceRpcPayload): 

1143 name = "DCE/RPC v5 - Request" 

1144 fields_desc = [ 

1145 _EField(IntField("alloc_hint", 0)), 

1146 _EField(ShortField("cont_id", 0)), 

1147 _EField(ShortField("opnum", 0)), 

1148 ConditionalField( 

1149 PadField( 

1150 _EField(UUIDField("object", None)), 

1151 align=8, 

1152 ), 

1153 lambda pkt: pkt.underlayer and pkt.underlayer.pfc_flags.PFC_OBJECT_UUID, 

1154 ), 

1155 ] 

1156 

1157 

1158bind_layers(DceRpc5, DceRpc5Request, ptype=0) 

1159 

1160# sec 12.6.4.10 

1161 

1162 

1163class DceRpc5Response(_DceRpcPayload): 

1164 name = "DCE/RPC v5 - Response" 

1165 fields_desc = [ 

1166 _EField(IntField("alloc_hint", 0)), 

1167 _EField(ShortField("cont_id", 0)), 

1168 ByteField("cancel_count", 0), 

1169 ByteField("reserved", 0), 

1170 ] 

1171 

1172 

1173bind_layers(DceRpc5, DceRpc5Response, ptype=2) 

1174 

1175# --- API 

1176 

1177DceRpcOp = collections.namedtuple("DceRpcOp", ["request", "response"]) 

1178DCE_RPC_INTERFACES = {} 

1179 

1180 

1181class DceRpcInterface: 

1182 def __init__(self, name, uuid, version_tuple, if_version, opnums): 

1183 self.name = name 

1184 self.uuid = uuid 

1185 self.major_version, self.minor_version = version_tuple 

1186 self.if_version = if_version 

1187 self.opnums = opnums 

1188 

1189 def __repr__(self): 

1190 return "<DCE/RPC Interface %s v%s.%s>" % ( 

1191 self.name, 

1192 self.major_version, 

1193 self.minor_version, 

1194 ) 

1195 

1196 

1197def register_dcerpc_interface(name, uuid, version, opnums): 

1198 """ 

1199 Register a DCE/RPC interface 

1200 """ 

1201 version_tuple = tuple(map(int, version.split("."))) 

1202 assert len(version_tuple) == 2, "Version should be in format 'X.X' !" 

1203 if_version = (version_tuple[1] << 16) + version_tuple[0] 

1204 if (uuid, if_version) in DCE_RPC_INTERFACES: 

1205 # Interface is already registered. 

1206 interface = DCE_RPC_INTERFACES[(uuid, if_version)] 

1207 if interface.name == name: 

1208 if set(opnums) - set(interface.opnums): 

1209 # Interface is an extension of a previous interface 

1210 interface.opnums.update(opnums) 

1211 else: 

1212 log_runtime.warning( 

1213 "This interface is already registered: %s. Skip" % interface 

1214 ) 

1215 return 

1216 else: 

1217 raise ValueError( 

1218 "An interface with the same UUID is already registered: %s" % interface 

1219 ) 

1220 else: 

1221 # New interface 

1222 DCE_RPC_INTERFACES_NAMES[uuid] = name 

1223 DCE_RPC_INTERFACES_NAMES_rev[name.lower()] = uuid 

1224 DCE_RPC_INTERFACES[(uuid, if_version)] = DceRpcInterface( 

1225 name, 

1226 uuid, 

1227 version_tuple, 

1228 if_version, 

1229 opnums, 

1230 ) 

1231 # bind for build 

1232 for opnum, operations in opnums.items(): 

1233 bind_top_down(DceRpc5Request, operations.request, opnum=opnum) 

1234 

1235 

1236def find_dcerpc_interface(name): 

1237 """ 

1238 Find an interface object through the name in the IDL 

1239 """ 

1240 try: 

1241 return next(x for x in DCE_RPC_INTERFACES.values() if x.name == name) 

1242 except StopIteration: 

1243 raise AttributeError("Unknown interface !") 

1244 

1245 

1246COM_INTERFACES = {} 

1247 

1248 

1249class ComInterface: 

1250 def __init__(self, name, uuid, opnums): 

1251 self.name = name 

1252 self.uuid = uuid 

1253 self.opnums = opnums 

1254 

1255 def __repr__(self): 

1256 return "<COM Interface %s>" % (self.name,) 

1257 

1258 

1259def register_com_interface(name, uuid, opnums): 

1260 """ 

1261 Register a COM interface 

1262 """ 

1263 COM_INTERFACES[uuid] = ComInterface( 

1264 name, 

1265 uuid, 

1266 opnums, 

1267 ) 

1268 

1269 

1270# --- NDR fields - [C706] chap 14 

1271 

1272 

1273def _set_ctx_on(f, obj): 

1274 if isinstance(f, _NDRPacket): 

1275 f.ndr64 = obj.ndr64 

1276 f.ndrendian = obj.ndrendian 

1277 if isinstance(f, list): 

1278 for x in f: 

1279 if isinstance(x, _NDRPacket): 

1280 x.ndr64 = obj.ndr64 

1281 x.ndrendian = obj.ndrendian 

1282 

1283 

1284def _e(ndrendian): 

1285 return {"big": ">", "little": "<"}[ndrendian] 

1286 

1287 

1288class _NDRPacket(Packet): 

1289 __slots__ = ["ndr64", "ndrendian", "deferred_pointers", "request_packet"] 

1290 

1291 def __init__(self, *args, **kwargs): 

1292 self.ndr64 = kwargs.pop("ndr64", False) 

1293 self.ndrendian = kwargs.pop("ndrendian", "little") 

1294 # request_packet is used in the session, so that a response packet 

1295 # can resolve union arms if the case parameter is in the request. 

1296 self.request_packet = kwargs.pop("request_packet", None) 

1297 self.deferred_pointers = [] 

1298 super(_NDRPacket, self).__init__(*args, **kwargs) 

1299 

1300 def do_dissect(self, s): 

1301 _up = self.parent or self.underlayer 

1302 if _up and isinstance(_up, _NDRPacket): 

1303 self.ndr64 = _up.ndr64 

1304 self.ndrendian = _up.ndrendian 

1305 else: 

1306 # See comment above NDRConstructedType 

1307 return NDRConstructedType([]).read_deferred_pointers( 

1308 self, super(_NDRPacket, self).do_dissect(s) 

1309 ) 

1310 return super(_NDRPacket, self).do_dissect(s) 

1311 

1312 def post_dissect(self, s): 

1313 if self.deferred_pointers: 

1314 # Can't trust the cache if there were deferred pointers 

1315 self.raw_packet_cache = None 

1316 return s 

1317 

1318 def do_build(self): 

1319 _up = self.parent or self.underlayer 

1320 for f in self.fields.values(): 

1321 _set_ctx_on(f, self) 

1322 if not _up or not isinstance(_up, _NDRPacket): 

1323 # See comment above NDRConstructedType 

1324 return NDRConstructedType([]).add_deferred_pointers( 

1325 self, super(_NDRPacket, self).do_build() 

1326 ) 

1327 return super(_NDRPacket, self).do_build() 

1328 

1329 def default_payload_class(self, pkt): 

1330 return conf.padding_layer 

1331 

1332 def clone_with(self, *args, **kwargs): 

1333 pkt = super(_NDRPacket, self).clone_with(*args, **kwargs) 

1334 # We need to copy deferred_pointers to not break pointer deferral 

1335 # on build. 

1336 pkt.deferred_pointers = self.deferred_pointers 

1337 pkt.ndr64 = self.ndr64 

1338 pkt.ndrendian = self.ndrendian 

1339 return pkt 

1340 

1341 def copy(self): 

1342 pkt = super(_NDRPacket, self).copy() 

1343 pkt.deferred_pointers = self.deferred_pointers 

1344 pkt.ndr64 = self.ndr64 

1345 pkt.ndrendian = self.ndrendian 

1346 return pkt 

1347 

1348 def show2(self, dump=False, indent=3, lvl="", label_lvl=""): 

1349 return self.__class__( 

1350 bytes(self), ndr64=self.ndr64, ndrendian=self.ndrendian 

1351 ).show(dump, indent, lvl, label_lvl) 

1352 

1353 def getfield_and_val(self, attr): 

1354 try: 

1355 return Packet.getfield_and_val(self, attr) 

1356 except ValueError: 

1357 if self.request_packet: 

1358 # Try to resolve the field from the request on failure 

1359 try: 

1360 return self.request_packet.getfield_and_val(attr) 

1361 except AttributeError: 

1362 pass 

1363 raise 

1364 

1365 def valueof(self, request): 

1366 """ 

1367 Util to get the value of a NDRField, ignoring arrays, pointers, etc. 

1368 """ 

1369 val = self 

1370 for ndr_field in request.split("."): 

1371 fld, fval = val.getfield_and_val(ndr_field) 

1372 val = fld.valueof(val, fval) 

1373 return val 

1374 

1375 

1376class _NDRAlign: 

1377 def padlen(self, flen, pkt): 

1378 return -flen % self._align[pkt.ndr64] 

1379 

1380 def original_length(self, pkt): 

1381 # Find the length of the NDR frag to be able to pad properly 

1382 while pkt: 

1383 par = pkt.parent or pkt.underlayer 

1384 if par and isinstance(par, _NDRPacket): 

1385 pkt = par 

1386 else: 

1387 break 

1388 return len(pkt.original) 

1389 

1390 

1391class NDRAlign(_NDRAlign, ReversePadField): 

1392 """ 

1393 ReversePadField modified to fit NDR. 

1394 

1395 - If no align size is specified, use the one from the inner field 

1396 - Size is calculated from the beginning of the NDR stream 

1397 """ 

1398 

1399 def __init__(self, fld, align, padwith=None): 

1400 super(NDRAlign, self).__init__(fld, align=align, padwith=padwith) 

1401 

1402 

1403class _VirtualField(Field): 

1404 # Hold a value but doesn't show up when building/dissecting 

1405 def addfield(self, pkt, s, x): 

1406 return s 

1407 

1408 def getfield(self, pkt, s): 

1409 return s, None 

1410 

1411 

1412class _NDRPacketMetaclass(Packet_metaclass): 

1413 def __new__(cls, name, bases, dct): 

1414 newcls = super(_NDRPacketMetaclass, cls).__new__(cls, name, bases, dct) 

1415 conformants = dct.get("DEPORTED_CONFORMANTS", []) 

1416 if conformants: 

1417 amount = len(conformants) 

1418 if amount == 1: 

1419 newcls.fields_desc.insert( 

1420 0, 

1421 _VirtualField("max_count", None), 

1422 ) 

1423 else: 

1424 newcls.fields_desc.insert( 

1425 0, 

1426 FieldListField( 

1427 "max_counts", 

1428 [], 

1429 _VirtualField("", 0), 

1430 count_from=lambda _: amount, 

1431 ), 

1432 ) 

1433 return newcls # type: ignore 

1434 

1435 

1436class NDRPacket(_NDRPacket, metaclass=_NDRPacketMetaclass): 

1437 """ 

1438 A NDR Packet. Handles pointer size & endianness 

1439 """ 

1440 

1441 __slots__ = ["_align"] 

1442 

1443 # NDR64 pad structures 

1444 # [MS-RPCE] 2.2.5.3.4.1 

1445 ALIGNMENT = (1, 1) 

1446 # [C706] sect 14.3.7 - Conformants max_count can be added to the beginning 

1447 DEPORTED_CONFORMANTS = [] 

1448 

1449 

1450# Primitive types 

1451 

1452 

1453class _NDRValueOf: 

1454 def valueof(self, pkt, x): 

1455 return x 

1456 

1457 

1458class _NDRLenField(_NDRValueOf, Field): 

1459 """ 

1460 Field similar to FieldLenField that takes size_of and adjust as arguments, 

1461 and take the value of a size on build. 

1462 """ 

1463 

1464 __slots__ = ["size_of", "adjust"] 

1465 

1466 def __init__(self, *args, **kwargs): 

1467 self.size_of = kwargs.pop("size_of", None) 

1468 self.adjust = kwargs.pop("adjust", lambda _, x: x) 

1469 super(_NDRLenField, self).__init__(*args, **kwargs) 

1470 

1471 def i2m(self, pkt, x): 

1472 if x is None and pkt is not None and self.size_of is not None: 

1473 fld, fval = pkt.getfield_and_val(self.size_of) 

1474 f = fld.i2len(pkt, fval) 

1475 x = self.adjust(pkt, f) 

1476 elif x is None: 

1477 x = 0 

1478 return x 

1479 

1480 

1481class NDRByteField(_NDRLenField, ByteField): 

1482 pass 

1483 

1484 

1485class NDRSignedByteField(_NDRLenField, SignedByteField): 

1486 pass 

1487 

1488 

1489class _NDRField(_NDRLenField): 

1490 FMT = "" 

1491 ALIGN = (0, 0) 

1492 

1493 def getfield(self, pkt, s): 

1494 return NDRAlign( 

1495 Field("", 0, fmt=_e(pkt.ndrendian) + self.FMT), align=self.ALIGN 

1496 ).getfield(pkt, s) 

1497 

1498 def addfield(self, pkt, s, val): 

1499 return NDRAlign( 

1500 Field("", 0, fmt=_e(pkt.ndrendian) + self.FMT), align=self.ALIGN 

1501 ).addfield(pkt, s, self.i2m(pkt, val)) 

1502 

1503 

1504class NDRShortField(_NDRField): 

1505 FMT = "H" 

1506 ALIGN = (2, 2) 

1507 

1508 

1509class NDRSignedShortField(_NDRField): 

1510 FMT = "h" 

1511 ALIGN = (2, 2) 

1512 

1513 

1514class NDRIntField(_NDRField): 

1515 FMT = "I" 

1516 ALIGN = (4, 4) 

1517 

1518 

1519class NDRSignedIntField(_NDRField): 

1520 FMT = "i" 

1521 ALIGN = (4, 4) 

1522 

1523 

1524class NDRLongField(_NDRField): 

1525 FMT = "Q" 

1526 ALIGN = (8, 8) 

1527 

1528 

1529class NDRSignedLongField(_NDRField): 

1530 FMT = "q" 

1531 ALIGN = (8, 8) 

1532 

1533 

1534class NDRIEEEFloatField(_NDRField): 

1535 FMT = "f" 

1536 ALIGN = (4, 4) 

1537 

1538 

1539class NDRIEEEDoubleField(_NDRField): 

1540 FMT = "d" 

1541 ALIGN = (8, 8) 

1542 

1543 

1544# Enum types 

1545 

1546 

1547class _NDREnumField(_NDRValueOf, EnumField): 

1548 # [MS-RPCE] sect 2.2.5.2 - Enums are 4 octets in NDR64 

1549 FMTS = ["H", "I"] 

1550 

1551 def getfield(self, pkt, s): 

1552 fmt = _e(pkt.ndrendian) + self.FMTS[pkt.ndr64] 

1553 return NDRAlign(Field("", 0, fmt=fmt), align=(2, 4)).getfield(pkt, s) 

1554 

1555 def addfield(self, pkt, s, val): 

1556 fmt = _e(pkt.ndrendian) + self.FMTS[pkt.ndr64] 

1557 return NDRAlign(Field("", 0, fmt=fmt), align=(2, 4)).addfield( 

1558 pkt, s, self.i2m(pkt, val) 

1559 ) 

1560 

1561 

1562class NDRInt3264EnumField(NDRAlign): 

1563 def __init__(self, *args, **kwargs): 

1564 super(NDRInt3264EnumField, self).__init__( 

1565 _NDREnumField(*args, **kwargs), align=(2, 4) 

1566 ) 

1567 

1568 

1569class NDRIntEnumField(_NDRValueOf, NDRAlign): 

1570 # v1_enum are always 4-octets, even in NDR32 

1571 def __init__(self, *args, **kwargs): 

1572 super(NDRIntEnumField, self).__init__( 

1573 LEIntEnumField(*args, **kwargs), align=(4, 4) 

1574 ) 

1575 

1576 

1577# Special types 

1578 

1579 

1580class NDRInt3264Field(_NDRLenField): 

1581 FMTS = ["I", "Q"] 

1582 

1583 def getfield(self, pkt, s): 

1584 fmt = _e(pkt.ndrendian) + self.FMTS[pkt.ndr64] 

1585 return NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield(pkt, s) 

1586 

1587 def addfield(self, pkt, s, val): 

1588 fmt = _e(pkt.ndrendian) + self.FMTS[pkt.ndr64] 

1589 return NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).addfield( 

1590 pkt, s, self.i2m(pkt, val) 

1591 ) 

1592 

1593 

1594class NDRSignedInt3264Field(NDRInt3264Field): 

1595 FMTS = ["i", "q"] 

1596 

1597 

1598# Pointer types 

1599 

1600 

1601class NDRPointer(_NDRPacket): 

1602 fields_desc = [ 

1603 MultipleTypeField( 

1604 [(XLELongField("referent_id", 1), lambda pkt: pkt and pkt.ndr64)], 

1605 XLEIntField("referent_id", 1), 

1606 ), 

1607 PacketField("value", None, conf.raw_layer), 

1608 ] 

1609 

1610 

1611class NDRFullPointerField(_FieldContainer): 

1612 """ 

1613 A NDR Full/Unique pointer field encapsulation. 

1614 

1615 :param deferred: This pointer is deferred. This means that it's representation 

1616 will not appear after the pointer. 

1617 See [C706] 14.3.12.3 - Algorithm for Deferral of Referents 

1618 """ 

1619 

1620 EMBEDDED = False 

1621 

1622 def __init__(self, fld, deferred=False, fmt="I"): 

1623 self.fld = fld 

1624 self.default = None 

1625 self.deferred = deferred 

1626 

1627 def getfield(self, pkt, s): 

1628 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

1629 remain, referent_id = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield( 

1630 pkt, s 

1631 ) 

1632 if not self.EMBEDDED and referent_id == 0: 

1633 return remain, None 

1634 if self.deferred: 

1635 # deferred 

1636 ptr = NDRPointer( 

1637 ndr64=pkt.ndr64, ndrendian=pkt.ndrendian, referent_id=referent_id 

1638 ) 

1639 pkt.deferred_pointers.append((ptr, partial(self.fld.getfield, pkt))) 

1640 return remain, ptr 

1641 remain, val = self.fld.getfield(pkt, remain) 

1642 return remain, NDRPointer( 

1643 ndr64=pkt.ndr64, ndrendian=pkt.ndrendian, referent_id=referent_id, value=val 

1644 ) 

1645 

1646 def addfield(self, pkt, s, val): 

1647 if val is not None and not isinstance(val, NDRPointer): 

1648 raise ValueError( 

1649 "Expected NDRPointer in %s. You are using it wrong!" % self.name 

1650 ) 

1651 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

1652 fld = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)) 

1653 if not self.EMBEDDED and val is None: 

1654 return fld.addfield(pkt, s, 0) 

1655 else: 

1656 _set_ctx_on(val.value, pkt) 

1657 s = fld.addfield(pkt, s, val.referent_id) 

1658 if self.deferred: 

1659 # deferred 

1660 pkt.deferred_pointers.append( 

1661 ((lambda s: self.fld.addfield(pkt, s, val.value)), val) 

1662 ) 

1663 return s 

1664 return self.fld.addfield(pkt, s, val.value) 

1665 

1666 def any2i(self, pkt, x): 

1667 # User-friendly helper 

1668 if x is not None and not isinstance(x, NDRPointer): 

1669 return NDRPointer( 

1670 referent_id=0x20000, 

1671 value=self.fld.any2i(pkt, x), 

1672 ) 

1673 return x 

1674 

1675 # Can't use i2repr = Field.i2repr and so on on PY2 :/ 

1676 def i2repr(self, pkt, val): 

1677 return repr(val) 

1678 

1679 def i2h(self, pkt, x): 

1680 return x 

1681 

1682 def h2i(self, pkt, x): 

1683 return x 

1684 

1685 def i2len(self, pkt, x): 

1686 if x is None: 

1687 return 0 

1688 return self.fld.i2len(pkt, x.value) 

1689 

1690 def valueof(self, pkt, x): 

1691 if x is None: 

1692 return x 

1693 return self.fld.valueof(pkt, x.value) 

1694 

1695 

1696class NDRRefEmbPointerField(NDRFullPointerField): 

1697 """ 

1698 A NDR Embedded Reference pointer 

1699 """ 

1700 

1701 EMBEDDED = True 

1702 

1703 

1704# Constructed types 

1705 

1706 

1707# Note: this is utterly complex and will drive you crazy 

1708 

1709# If you have a NDRPacket that contains a deferred pointer on the top level 

1710# (only happens in non DCE/RPC structures, such as in MS-PAC, where you have an NDR 

1711# structure encapsulated in a non-NDR structure), there will be left-over deferred 

1712# pointers when exiting dissection/build (deferred pointers are only computed when 

1713# reaching a field that extends NDRConstructedType, which is normal: if you follow 

1714# the DCE/RPC spec, pointers are never deferred in root structures) 

1715# Therefore there is a special case forcing the build/dissection of any leftover 

1716# pointers in NDRPacket, if Scapy detects that they won't be handled by any parent. 

1717 

1718# Implementation notes: I chose to set 'handles_deferred' inside the FIELD, rather 

1719# than inside the PACKET. This is faster to compute because whether a constructed type 

1720# should handle deferral or not is computed only once when loading, therefore Scapy 

1721# knows in advance whether to handle deferred pointers or not. But it is technically 

1722# incorrect: with this approach, a structure (packet) cannot be used in 2 code paths 

1723# that have different pointer managements. I mean by that that if there was a 

1724# structure that was directly embedded in a RPC request without a pointer but also 

1725# embedded with a pointer in another RPC request, it would break. 

1726# Fortunately this isn't the case: structures are never reused for 2 purposes. 

1727# (or at least I never seen that... <i hope this works>) 

1728 

1729 

1730class NDRConstructedType(object): 

1731 def __init__(self, fields): 

1732 self.handles_deferred = False 

1733 self.ndr_fields = fields 

1734 self.rec_check_deferral() 

1735 

1736 def rec_check_deferral(self): 

1737 # We iterate through the fields within this constructed type. 

1738 # If we have a pointer, mark this field as handling deferrance 

1739 # and make all sub-constructed types not. 

1740 for f in self.ndr_fields: 

1741 if isinstance(f, NDRFullPointerField) and f.deferred: 

1742 self.handles_deferred = True 

1743 if isinstance(f, NDRConstructedType): 

1744 f.rec_check_deferral() 

1745 if f.handles_deferred: 

1746 self.handles_deferred = True 

1747 f.handles_deferred = False 

1748 

1749 def getfield(self, pkt, s): 

1750 s, fval = super(NDRConstructedType, self).getfield(pkt, s) 

1751 if isinstance(fval, _NDRPacket): 

1752 # If a sub-packet we just dissected has deferred pointers, 

1753 # pass it to parent packet to propagate. 

1754 pkt.deferred_pointers.extend(fval.deferred_pointers) 

1755 del fval.deferred_pointers[:] 

1756 if self.handles_deferred: 

1757 # This field handles deferral ! 

1758 s = self.read_deferred_pointers(pkt, s) 

1759 return s, fval 

1760 

1761 def read_deferred_pointers(self, pkt, s): 

1762 # Now read content of the pointers that were deferred 

1763 q = collections.deque() 

1764 q.extend(pkt.deferred_pointers) 

1765 del pkt.deferred_pointers[:] 

1766 while q: 

1767 # Recursively resolve pointers that were deferred 

1768 ptr, getfld = q.popleft() 

1769 s, val = getfld(s) 

1770 ptr.value = val 

1771 if isinstance(val, _NDRPacket): 

1772 # Pointer resolves to a packet.. that may have deferred pointers? 

1773 q.extend(val.deferred_pointers) 

1774 del val.deferred_pointers[:] 

1775 return s 

1776 

1777 def addfield(self, pkt, s, val): 

1778 s = super(NDRConstructedType, self).addfield(pkt, s, val) 

1779 if isinstance(val, _NDRPacket): 

1780 # If a sub-packet we just dissected has deferred pointers, 

1781 # pass it to parent packet to propagate. 

1782 pkt.deferred_pointers.extend(val.deferred_pointers) 

1783 del val.deferred_pointers[:] 

1784 if self.handles_deferred: 

1785 # This field handles deferral ! 

1786 s = self.add_deferred_pointers(pkt, s) 

1787 return s 

1788 

1789 def add_deferred_pointers(self, pkt, s): 

1790 # Now add content of pointers that were deferred 

1791 q = collections.deque() 

1792 q.extend(pkt.deferred_pointers) 

1793 del pkt.deferred_pointers[:] 

1794 while q: 

1795 addfld, fval = q.popleft() 

1796 s = addfld(s) 

1797 if isinstance(fval, NDRPointer) and isinstance(fval.value, _NDRPacket): 

1798 q.extend(fval.value.deferred_pointers) 

1799 del fval.value.deferred_pointers[:] 

1800 return s 

1801 

1802 

1803class _NDRPacketField(_NDRValueOf, PacketField): 

1804 def m2i(self, pkt, m): 

1805 return self.cls(m, ndr64=pkt.ndr64, ndrendian=pkt.ndrendian, _parent=pkt) 

1806 

1807 

1808class _NDRPacketPadField(PadField): 

1809 # [MS-RPCE] 2.2.5.3.4.1 Structure with Trailing Gap 

1810 # Structures have extra alignment/padding in NDR64. 

1811 def padlen(self, flen, pkt): 

1812 if pkt.ndr64: 

1813 return -flen % self._align[1] 

1814 else: 

1815 return 0 

1816 

1817 

1818class NDRPacketField(NDRConstructedType, NDRAlign): 

1819 def __init__(self, name, default, pkt_cls, **kwargs): 

1820 self.DEPORTED_CONFORMANTS = pkt_cls.DEPORTED_CONFORMANTS 

1821 self.fld = _NDRPacketField(name, default, pkt_cls=pkt_cls, **kwargs) 

1822 NDRAlign.__init__( 

1823 self, 

1824 _NDRPacketPadField(self.fld, align=pkt_cls.ALIGNMENT), 

1825 align=pkt_cls.ALIGNMENT, 

1826 ) 

1827 NDRConstructedType.__init__(self, pkt_cls.fields_desc) 

1828 

1829 def getfield(self, pkt, x): 

1830 # Handle deformed conformants max_count here 

1831 if self.DEPORTED_CONFORMANTS: 

1832 # C706 14.3.2: "In other words, the size information precedes the 

1833 # structure and is aligned independently of the structure alignment." 

1834 fld = NDRInt3264Field("", 0) 

1835 max_counts = [] 

1836 for _ in self.DEPORTED_CONFORMANTS: 

1837 x, max_count = fld.getfield(pkt, x) 

1838 max_counts.append(max_count) 

1839 res, val = super(NDRPacketField, self).getfield(pkt, x) 

1840 if len(max_counts) == 1: 

1841 val.max_count = max_counts[0] 

1842 else: 

1843 val.max_counts = max_counts 

1844 return res, val 

1845 return super(NDRPacketField, self).getfield(pkt, x) 

1846 

1847 def addfield(self, pkt, s, x): 

1848 # Handle deformed conformants max_count here 

1849 if self.DEPORTED_CONFORMANTS: 

1850 mcfld = NDRInt3264Field("", 0) 

1851 if len(self.DEPORTED_CONFORMANTS) == 1: 

1852 max_counts = [x.max_count] 

1853 else: 

1854 max_counts = x.max_counts 

1855 for fldname, max_count in zip(self.DEPORTED_CONFORMANTS, max_counts): 

1856 if max_count is None: 

1857 fld, val = x.getfield_and_val(fldname) 

1858 max_count = fld.i2len(x, val) 

1859 s = mcfld.addfield(pkt, s, max_count) 

1860 return super(NDRPacketField, self).addfield(pkt, s, x) 

1861 return super(NDRPacketField, self).addfield(pkt, s, x) 

1862 

1863 

1864# Array types 

1865 

1866 

1867class _NDRPacketListField(NDRConstructedType, PacketListField): 

1868 """ 

1869 A PacketListField for NDR that can optionally pack the packets into NDRPointers 

1870 """ 

1871 

1872 islist = 1 

1873 holds_packets = 1 

1874 

1875 __slots__ = ["ptr_pack", "fld"] 

1876 

1877 def __init__(self, name, default, pkt_cls, **kwargs): 

1878 self.ptr_pack = kwargs.pop("ptr_pack", False) 

1879 if self.ptr_pack: 

1880 self.fld = NDRFullPointerField( 

1881 NDRPacketField("", None, pkt_cls), deferred=True 

1882 ) 

1883 else: 

1884 self.fld = NDRPacketField("", None, pkt_cls) 

1885 PacketListField.__init__(self, name, default, pkt_cls=pkt_cls, **kwargs) 

1886 NDRConstructedType.__init__(self, [self.fld]) 

1887 

1888 def m2i(self, pkt, s): 

1889 remain, val = self.fld.getfield(pkt, s) 

1890 # A mistake here would be to use / instead of add_payload. It adds a copy 

1891 # which breaks pointer defferal. Same applies elsewhere 

1892 val.add_payload(conf.padding_layer(remain)) 

1893 return val 

1894 

1895 def any2i(self, pkt, x): 

1896 # User-friendly helper 

1897 if isinstance(x, list): 

1898 x = [self.fld.any2i(pkt, y) for y in x] 

1899 return super(_NDRPacketListField, self).any2i(pkt, x) 

1900 

1901 def i2m(self, pkt, val): 

1902 return self.fld.addfield(pkt, b"", val) 

1903 

1904 def i2len(self, pkt, x): 

1905 return len(x) 

1906 

1907 def valueof(self, pkt, x): 

1908 return [self.fld.valueof(pkt, y) for y in x] 

1909 

1910 

1911class NDRFieldListField(NDRConstructedType, FieldListField): 

1912 """ 

1913 A FieldListField for NDR 

1914 """ 

1915 

1916 islist = 1 

1917 

1918 def __init__(self, *args, **kwargs): 

1919 kwargs.pop("ptr_pack", None) # TODO: unimplemented 

1920 if "length_is" in kwargs: 

1921 kwargs["count_from"] = kwargs.pop("length_is") 

1922 elif "size_is" in kwargs: 

1923 kwargs["count_from"] = kwargs.pop("size_is") 

1924 FieldListField.__init__(self, *args, **kwargs) 

1925 NDRConstructedType.__init__(self, [self.field]) 

1926 

1927 def i2len(self, pkt, x): 

1928 return len(x) 

1929 

1930 def valueof(self, pkt, x): 

1931 return [self.field.valueof(pkt, y) for y in x] 

1932 

1933 

1934class NDRVaryingArray(_NDRPacket): 

1935 fields_desc = [ 

1936 MultipleTypeField( 

1937 [(LELongField("offset", 0), lambda pkt: pkt and pkt.ndr64)], 

1938 LEIntField("offset", 0), 

1939 ), 

1940 MultipleTypeField( 

1941 [ 

1942 ( 

1943 LELongField("actual_count", None), 

1944 lambda pkt: pkt and pkt.ndr64, 

1945 ) 

1946 ], 

1947 LEIntField("actual_count", None), 

1948 ), 

1949 PacketField("value", None, conf.raw_layer), 

1950 ] 

1951 

1952 

1953class _NDRVarField(object): 

1954 """ 

1955 NDR Varying Array / String field 

1956 """ 

1957 

1958 LENGTH_FROM = False 

1959 COUNT_FROM = False 

1960 

1961 def __init__(self, *args, **kwargs): 

1962 # size is either from the length_is, if specified, or the "actual_count" 

1963 self.from_actual = "length_is" not in kwargs 

1964 length_is = kwargs.pop("length_is", lambda pkt: pkt.actual_count) 

1965 if self.LENGTH_FROM: 

1966 kwargs["length_from"] = length_is 

1967 elif self.COUNT_FROM: 

1968 kwargs["count_from"] = length_is 

1969 super(_NDRVarField, self).__init__(*args, **kwargs) 

1970 

1971 def getfield(self, pkt, s): 

1972 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

1973 remain, offset = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield(pkt, s) 

1974 remain, actual_count = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield( 

1975 pkt, remain 

1976 ) 

1977 final = NDRVaryingArray( 

1978 ndr64=pkt.ndr64, 

1979 ndrendian=pkt.ndrendian, 

1980 offset=offset, 

1981 actual_count=actual_count, 

1982 ) 

1983 if self.from_actual: 

1984 remain, val = super(_NDRVarField, self).getfield(final, remain) 

1985 else: 

1986 remain, val = super(_NDRVarField, self).getfield(pkt, remain) 

1987 final.value = super(_NDRVarField, self).i2h(pkt, val) 

1988 return remain, final 

1989 

1990 def addfield(self, pkt, s, val): 

1991 if not isinstance(val, NDRVaryingArray): 

1992 raise ValueError( 

1993 "Expected NDRVaryingArray in %s. You are using it wrong!" % self.name 

1994 ) 

1995 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

1996 _set_ctx_on(val.value, pkt) 

1997 s = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).addfield(pkt, s, val.offset) 

1998 s = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).addfield( 

1999 pkt, 

2000 s, 

2001 val.actual_count is None 

2002 and super(_NDRVarField, self).i2len(pkt, val.value) 

2003 or val.actual_count, 

2004 ) 

2005 return super(_NDRVarField, self).addfield( 

2006 pkt, s, super(_NDRVarField, self).h2i(pkt, val.value) 

2007 ) 

2008 

2009 def i2len(self, pkt, x): 

2010 return super(_NDRVarField, self).i2len(pkt, x.value) 

2011 

2012 def any2i(self, pkt, x): 

2013 # User-friendly helper 

2014 if not isinstance(x, NDRVaryingArray): 

2015 return NDRVaryingArray( 

2016 value=super(_NDRVarField, self).any2i(pkt, x), 

2017 ) 

2018 return x 

2019 

2020 # Can't use i2repr = Field.i2repr and so on on PY2 :/ 

2021 def i2repr(self, pkt, val): 

2022 return repr(val) 

2023 

2024 def i2h(self, pkt, x): 

2025 return x 

2026 

2027 def h2i(self, pkt, x): 

2028 return x 

2029 

2030 def valueof(self, pkt, x): 

2031 return super(_NDRVarField, self).valueof(pkt, x.value) 

2032 

2033 

2034class NDRConformantArray(_NDRPacket): 

2035 fields_desc = [ 

2036 MultipleTypeField( 

2037 [(LELongField("max_count", None), lambda pkt: pkt and pkt.ndr64)], 

2038 LEIntField("max_count", None), 

2039 ), 

2040 MultipleTypeField( 

2041 [ 

2042 ( 

2043 PacketListField( 

2044 "value", 

2045 [], 

2046 conf.raw_layer, 

2047 count_from=lambda pkt: pkt.max_count, 

2048 ), 

2049 ( 

2050 lambda pkt: pkt.fields.get("value", None) 

2051 and isinstance(pkt.fields["value"][0], Packet), 

2052 lambda _, val: val and isinstance(val[0], Packet), 

2053 ), 

2054 ) 

2055 ], 

2056 FieldListField( 

2057 "value", [], LEIntField("", 0), count_from=lambda pkt: pkt.max_count 

2058 ), 

2059 ), 

2060 ] 

2061 

2062 

2063class NDRConformantString(_NDRPacket): 

2064 fields_desc = [ 

2065 MultipleTypeField( 

2066 [(LELongField("max_count", None), lambda pkt: pkt and pkt.ndr64)], 

2067 LEIntField("max_count", None), 

2068 ), 

2069 StrField("value", ""), 

2070 ] 

2071 

2072 

2073class _NDRConfField(object): 

2074 """ 

2075 NDR Conformant Array / String field 

2076 """ 

2077 

2078 CONFORMANT_STRING = False 

2079 LENGTH_FROM = False 

2080 COUNT_FROM = False 

2081 

2082 def __init__(self, *args, **kwargs): 

2083 self.conformant_in_struct = kwargs.pop("conformant_in_struct", False) 

2084 # size_is/max_is end up here, and is what defines a conformant field. 

2085 if "size_is" in kwargs: 

2086 size_is = kwargs.pop("size_is") 

2087 if self.LENGTH_FROM: 

2088 kwargs["length_from"] = size_is 

2089 elif self.COUNT_FROM: 

2090 kwargs["count_from"] = size_is 

2091 super(_NDRConfField, self).__init__(*args, **kwargs) 

2092 

2093 def getfield(self, pkt, s): 

2094 # [C706] - 14.3.7 Structures Containing Arrays 

2095 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

2096 if self.conformant_in_struct: 

2097 return super(_NDRConfField, self).getfield(pkt, s) 

2098 remain, max_count = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield( 

2099 pkt, s 

2100 ) 

2101 remain, val = super(_NDRConfField, self).getfield(pkt, remain) 

2102 return remain, ( 

2103 NDRConformantString if self.CONFORMANT_STRING else NDRConformantArray 

2104 )(ndr64=pkt.ndr64, ndrendian=pkt.ndrendian, max_count=max_count, value=val) 

2105 

2106 def addfield(self, pkt, s, val): 

2107 if self.conformant_in_struct: 

2108 return super(_NDRConfField, self).addfield(pkt, s, val) 

2109 if self.CONFORMANT_STRING and not isinstance(val, NDRConformantString): 

2110 raise ValueError( 

2111 "Expected NDRConformantString in %s. You are using it wrong!" 

2112 % self.name 

2113 ) 

2114 elif not self.CONFORMANT_STRING and not isinstance(val, NDRConformantArray): 

2115 raise ValueError( 

2116 "Expected NDRConformantArray in %s. You are using it wrong!" % self.name 

2117 ) 

2118 fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64] 

2119 _set_ctx_on(val.value, pkt) 

2120 if val.value and isinstance(val.value[0], NDRVaryingArray): 

2121 value = val.value[0] 

2122 else: 

2123 value = val.value 

2124 s = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).addfield( 

2125 pkt, 

2126 s, 

2127 val.max_count is None 

2128 and super(_NDRConfField, self).i2len(pkt, value) 

2129 or val.max_count, 

2130 ) 

2131 return super(_NDRConfField, self).addfield(pkt, s, value) 

2132 

2133 def _subval(self, x): 

2134 if self.conformant_in_struct: 

2135 value = x 

2136 elif ( 

2137 not self.CONFORMANT_STRING 

2138 and x.value 

2139 and isinstance(x.value[0], NDRVaryingArray) 

2140 ): 

2141 value = x.value[0] 

2142 else: 

2143 value = x.value 

2144 return value 

2145 

2146 def i2len(self, pkt, x): 

2147 return super(_NDRConfField, self).i2len(pkt, self._subval(x)) 

2148 

2149 def any2i(self, pkt, x): 

2150 # User-friendly helper 

2151 if self.conformant_in_struct: 

2152 return super(_NDRConfField, self).any2i(pkt, x) 

2153 if self.CONFORMANT_STRING and not isinstance(x, NDRConformantString): 

2154 return NDRConformantString( 

2155 value=super(_NDRConfField, self).any2i(pkt, x), 

2156 ) 

2157 elif not isinstance(x, NDRConformantArray): 

2158 return NDRConformantArray( 

2159 value=super(_NDRConfField, self).any2i(pkt, x), 

2160 ) 

2161 return x 

2162 

2163 # Can't use i2repr = Field.i2repr and so on on PY2 :/ 

2164 def i2repr(self, pkt, val): 

2165 return repr(val) 

2166 

2167 def i2h(self, pkt, x): 

2168 return x 

2169 

2170 def h2i(self, pkt, x): 

2171 return x 

2172 

2173 def valueof(self, pkt, x): 

2174 return super(_NDRConfField, self).valueof(pkt, self._subval(x)) 

2175 

2176 

2177class NDRVarPacketListField(_NDRVarField, _NDRPacketListField): 

2178 """ 

2179 NDR Varying PacketListField. Unused 

2180 """ 

2181 

2182 COUNT_FROM = True 

2183 

2184 

2185class NDRConfPacketListField(_NDRConfField, _NDRPacketListField): 

2186 """ 

2187 NDR Conformant PacketListField 

2188 """ 

2189 

2190 COUNT_FROM = True 

2191 

2192 

2193class NDRConfVarPacketListField(_NDRConfField, _NDRVarField, _NDRPacketListField): 

2194 """ 

2195 NDR Conformant Varying PacketListField 

2196 """ 

2197 

2198 COUNT_FROM = True 

2199 

2200 

2201class NDRConfFieldListField(_NDRConfField, NDRFieldListField): 

2202 """ 

2203 NDR Conformant FieldListField 

2204 """ 

2205 

2206 COUNT_FROM = True 

2207 

2208 

2209class NDRConfVarFieldListField(_NDRConfField, _NDRVarField, NDRFieldListField): 

2210 """ 

2211 NDR Conformant Varying FieldListField 

2212 """ 

2213 

2214 COUNT_FROM = True 

2215 

2216 

2217# NDR String fields 

2218 

2219 

2220class _NDRUtf16(Field): 

2221 def h2i(self, pkt, x): 

2222 encoding = {"big": "utf-16be", "little": "utf-16le"}[pkt.ndrendian] 

2223 return plain_str(x).encode(encoding) 

2224 

2225 def i2h(self, pkt, x): 

2226 encoding = {"big": "utf-16be", "little": "utf-16le"}[pkt.ndrendian] 

2227 return bytes_encode(x).decode(encoding, errors="replace") 

2228 

2229 

2230class NDRConfStrLenField(_NDRConfField, _NDRValueOf, StrLenField): 

2231 """ 

2232 NDR Conformant StrLenField. 

2233 

2234 This is not a "string" per NDR, but an a conformant byte array 

2235 (e.g. tower_octet_string) 

2236 """ 

2237 

2238 CONFORMANT_STRING = True 

2239 LENGTH_FROM = True 

2240 

2241 

2242class NDRConfStrLenFieldUtf16(_NDRConfField, _NDRValueOf, StrLenFieldUtf16, _NDRUtf16): 

2243 """ 

2244 NDR Conformant StrLenField. 

2245 

2246 See NDRConfLenStrField for comment. 

2247 """ 

2248 

2249 CONFORMANT_STRING = True 

2250 ON_WIRE_SIZE_UTF16 = False 

2251 LENGTH_FROM = True 

2252 

2253 

2254class NDRVarStrLenField(_NDRVarField, StrLenField): 

2255 """ 

2256 NDR Varying StrLenField 

2257 """ 

2258 

2259 LENGTH_FROM = True 

2260 

2261 

2262class NDRVarStrLenFieldUtf16(_NDRVarField, _NDRValueOf, StrLenFieldUtf16, _NDRUtf16): 

2263 """ 

2264 NDR Varying StrLenField 

2265 """ 

2266 

2267 ON_WIRE_SIZE_UTF16 = False 

2268 LENGTH_FROM = True 

2269 

2270 

2271class NDRConfVarStrLenField(_NDRConfField, _NDRVarField, _NDRValueOf, StrLenField): 

2272 """ 

2273 NDR Conformant Varying StrLenField 

2274 """ 

2275 

2276 LENGTH_FROM = True 

2277 

2278 

2279class NDRConfVarStrLenFieldUtf16( 

2280 _NDRConfField, _NDRVarField, _NDRValueOf, StrLenFieldUtf16, _NDRUtf16 

2281): 

2282 """ 

2283 NDR Conformant Varying StrLenField 

2284 """ 

2285 

2286 ON_WIRE_SIZE_UTF16 = False 

2287 LENGTH_FROM = True 

2288 

2289 

2290class NDRConfVarStrNullField(_NDRConfField, _NDRVarField, _NDRValueOf, StrNullField): 

2291 """ 

2292 NDR Conformant Varying StrNullField 

2293 """ 

2294 

2295 NULLFIELD = True 

2296 

2297 

2298class NDRConfVarStrNullFieldUtf16( 

2299 _NDRConfField, _NDRVarField, _NDRValueOf, StrNullFieldUtf16, _NDRUtf16 

2300): 

2301 """ 

2302 NDR Conformant Varying StrNullFieldUtf16 

2303 """ 

2304 

2305 ON_WIRE_SIZE_UTF16 = False 

2306 NULLFIELD = True 

2307 

2308 

2309# Union type 

2310 

2311 

2312class NDRUnion(_NDRPacket): 

2313 fields_desc = [ 

2314 IntField("tag", 0), 

2315 PacketField("value", None, conf.raw_layer), 

2316 ] 

2317 

2318 

2319class _NDRUnionField(MultipleTypeField): 

2320 __slots__ = ["switch_fmt", "align"] 

2321 

2322 def __init__(self, flds, dflt, align, switch_fmt): 

2323 self.switch_fmt = switch_fmt 

2324 self.align = align 

2325 super(_NDRUnionField, self).__init__(flds, dflt) 

2326 

2327 def getfield(self, pkt, s): 

2328 fmt = _e(pkt.ndrendian) + self.switch_fmt[pkt.ndr64] 

2329 remain, tag = NDRAlign(Field("", 0, fmt=fmt), align=self.align).getfield(pkt, s) 

2330 fld, _ = super(_NDRUnionField, self)._find_fld_pkt_val(pkt, NDRUnion(tag=tag)) 

2331 remain, val = fld.getfield(pkt, remain) 

2332 return remain, NDRUnion( 

2333 tag=tag, value=val, ndr64=pkt.ndr64, ndrendian=pkt.ndrendian, _parent=pkt 

2334 ) 

2335 

2336 def addfield(self, pkt, s, val): 

2337 fmt = _e(pkt.ndrendian) + self.switch_fmt[pkt.ndr64] 

2338 if not isinstance(val, NDRUnion): 

2339 raise ValueError( 

2340 "Expected NDRUnion in %s. You are using it wrong!" % self.name 

2341 ) 

2342 _set_ctx_on(val.value, pkt) 

2343 # First, align the whole tag+union against the align param 

2344 s = NDRAlign(Field("", 0, fmt=fmt), align=self.align).addfield(pkt, s, val.tag) 

2345 # Then, compute the subfield with its own alignment 

2346 return super(_NDRUnionField, self).addfield(pkt, s, val) 

2347 

2348 def _find_fld_pkt_val(self, pkt, val): 

2349 fld, val = super(_NDRUnionField, self)._find_fld_pkt_val(pkt, val) 

2350 return fld, val.value 

2351 

2352 # Can't use i2repr = Field.i2repr and so on on PY2 :/ 

2353 def i2repr(self, pkt, val): 

2354 return repr(val) 

2355 

2356 def i2h(self, pkt, x): 

2357 return x 

2358 

2359 def h2i(self, pkt, x): 

2360 return x 

2361 

2362 def valueof(self, pkt, x): 

2363 fld, val = self._find_fld_pkt_val(pkt, x) 

2364 return fld.valueof(pkt, x.value) 

2365 

2366 

2367class NDRUnionField(NDRConstructedType, _NDRUnionField): 

2368 def __init__(self, flds, dflt, align, switch_fmt): 

2369 _NDRUnionField.__init__(self, flds, dflt, align=align, switch_fmt=switch_fmt) 

2370 NDRConstructedType.__init__(self, [x[0] for x in flds] + [dflt]) 

2371 

2372 def any2i(self, pkt, x): 

2373 # User-friendly helper 

2374 if x: 

2375 if not isinstance(x, NDRUnion): 

2376 raise ValueError("Invalid value for %s; should be NDRUnion" % self.name) 

2377 else: 

2378 x.value = _NDRUnionField.any2i(self, pkt, x) 

2379 return x 

2380 

2381 

2382# Misc 

2383 

2384 

2385class NDRRecursiveField(Field): 

2386 """ 

2387 A special Field that is used for pointer recursion 

2388 """ 

2389 

2390 def __init__(self, name, fmt="I"): 

2391 super(NDRRecursiveField, self).__init__(name, None, fmt=fmt) 

2392 

2393 def getfield(self, pkt, s): 

2394 return NDRFullPointerField( 

2395 NDRPacketField("", None, pkt.__class__), deferred=True 

2396 ).getfield(pkt, s) 

2397 

2398 def addfield(self, pkt, s, val): 

2399 return NDRFullPointerField( 

2400 NDRPacketField("", None, pkt.__class__), deferred=True 

2401 ).addfield(pkt, s, val) 

2402 

2403 

2404# The very few NDR-specific structures 

2405 

2406 

2407class NDRContextHandle(NDRPacket): 

2408 ALIGNMENT = (4, 4) 

2409 fields_desc = [ 

2410 LEIntField("attributes", 0), 

2411 StrFixedLenField("uuid", b"", length=16), 

2412 ] 

2413 

2414 def guess_payload_class(self, payload): 

2415 return conf.padding_layer 

2416 

2417 

2418# --- Type Serialization Version 1 - [MSRPCE] sect 2.2.6 

2419 

2420 

2421def _get_ndrtype1_endian(pkt): 

2422 if pkt.underlayer is None: 

2423 return "<" 

2424 return {0x00: ">", 0x10: "<"}.get(pkt.underlayer.Endianness, "<") 

2425 

2426 

2427class NDRSerialization1Header(Packet): 

2428 fields_desc = [ 

2429 ByteField("Version", 1), 

2430 ByteEnumField("Endianness", 0x10, {0x00: "big", 0x10: "little"}), 

2431 LEShortField("CommonHeaderLength", 8), 

2432 XLEIntField("Filler", 0xCCCCCCCC), 

2433 ] 

2434 

2435 

2436class NDRSerialization1PrivateHeader(Packet): 

2437 fields_desc = [ 

2438 EField( 

2439 LEIntField("ObjectBufferLength", 0), endianness_from=_get_ndrtype1_endian 

2440 ), 

2441 XLEIntField("Filler", 0), 

2442 ] 

2443 

2444 

2445def ndr_deserialize1(b, cls, ndr64=False): 

2446 """ 

2447 Deserialize Type Serialization Version 1 according to [MS-RPCE] sect 2.2.6 

2448 """ 

2449 if issubclass(cls, NDRPacket): 

2450 # We use an intermediary class for two reasons: 

2451 # - it properly sets deferred pointers 

2452 # - it uses NDRPacketField which handles deported conformant fields 

2453 class _cls(NDRPacket): 

2454 fields_desc = [ 

2455 NDRFullPointerField(NDRPacketField("pkt", None, cls)), 

2456 ] 

2457 

2458 hdr = NDRSerialization1Header(b[:8]) / NDRSerialization1PrivateHeader(b[8:16]) 

2459 endian = {0x00: "big", 0x10: "little"}[hdr.Endianness] 

2460 padlen = (-hdr.ObjectBufferLength) % _TYPE1_S_PAD 

2461 # padlen should be 0 (pad included in length), but some implementations 

2462 # implement apparently misread the spec 

2463 return ( 

2464 hdr 

2465 / _cls( 

2466 b[16 : 20 + hdr.ObjectBufferLength], 

2467 ndr64=ndr64, 

2468 ndrendian=endian, 

2469 ).pkt 

2470 / conf.padding_layer(b[20 + padlen + hdr.ObjectBufferLength :]) 

2471 ) 

2472 return NDRSerialization1Header(b[:8]) / cls(b[8:]) 

2473 

2474 

2475def ndr_serialize1(pkt): 

2476 """ 

2477 Serialize Type Serialization Version 1 

2478 """ 

2479 pkt = pkt.copy() 

2480 endian = getattr(pkt, "ndrendian", "little") 

2481 if not isinstance(pkt, NDRSerialization1Header): 

2482 if not isinstance(pkt, NDRPacket): 

2483 return bytes(NDRSerialization1Header(Endianness=endian) / pkt) 

2484 if isinstance(pkt, NDRPointer): 

2485 cls = pkt.value.__class__ 

2486 else: 

2487 cls = pkt.__class__ 

2488 val = pkt 

2489 pkt_len = len(pkt) 

2490 # ObjectBufferLength: 

2491 # > It MUST include the padding length and exclude the header itself 

2492 pkt = NDRSerialization1Header( 

2493 Endianness=endian 

2494 ) / NDRSerialization1PrivateHeader( 

2495 ObjectBufferLength=pkt_len + (-pkt_len) % _TYPE1_S_PAD 

2496 ) 

2497 else: 

2498 cls = pkt.value.__class__ 

2499 val = pkt.payload.payload 

2500 pkt.payload.remove_payload() 

2501 

2502 # See above about why we need an intermediary class 

2503 class _cls(NDRPacket): 

2504 fields_desc = [ 

2505 NDRFullPointerField(NDRPacketField("pkt", None, cls)), 

2506 ] 

2507 

2508 ret = bytes(pkt / _cls(pkt=val)) 

2509 return ret + (-len(ret) % _TYPE1_S_PAD) * b"\x00" 

2510 

2511 

2512class _NDRSerializeType1: 

2513 def __init__(self, *args, **kwargs): 

2514 super(_NDRSerializeType1, self).__init__(*args, **kwargs) 

2515 

2516 def i2m(self, pkt, val): 

2517 return ndr_serialize1(val) 

2518 

2519 def m2i(self, pkt, s): 

2520 return ndr_deserialize1(s, self.cls, ndr64=False) 

2521 

2522 def i2len(self, pkt, val): 

2523 return len(self.i2m(pkt, val)) 

2524 

2525 

2526class NDRSerializeType1PacketField(_NDRSerializeType1, PacketField): 

2527 __slots__ = ["ptr"] 

2528 

2529 

2530class NDRSerializeType1PacketLenField(_NDRSerializeType1, PacketLenField): 

2531 __slots__ = ["ptr"] 

2532 

2533 

2534class NDRSerializeType1PacketListField(_NDRSerializeType1, PacketListField): 

2535 __slots__ = ["ptr"] 

2536 

2537 

2538# --- DCE/RPC session 

2539 

2540 

2541class DceRpcSession(DefaultSession): 

2542 """ 

2543 A DCE/RPC session within a TCP socket. 

2544 """ 

2545 

2546 def __init__(self, *args, **kwargs): 

2547 self.rpc_bind_interface = None 

2548 self.ndr64 = False 

2549 self.ndrendian = "little" 

2550 self.support_header_signing = kwargs.pop("support_header_signing", True) 

2551 self.header_sign = conf.dcerpc_force_header_signing 

2552 self.ssp = kwargs.pop("ssp", None) 

2553 self.sspcontext = kwargs.pop("sspcontext", None) 

2554 self.auth_level = kwargs.pop("auth_level", None) 

2555 self.auth_context_id = kwargs.pop("auth_context_id", 0) 

2556 self.map_callid_opnum = {} 

2557 self.frags = collections.defaultdict(lambda: b"") 

2558 self.sniffsspcontexts = {} # Unfinished contexts for passive 

2559 if conf.dcerpc_session_enable and conf.winssps_passive: 

2560 for ssp in conf.winssps_passive: 

2561 self.sniffsspcontexts[ssp] = None 

2562 super(DceRpcSession, self).__init__(*args, **kwargs) 

2563 

2564 def _up_pkt(self, pkt): 

2565 """ 

2566 Common function to handle the DCE/RPC session: what interfaces are bind, 

2567 opnums, etc. 

2568 """ 

2569 opnum = None 

2570 opts = {} 

2571 if DceRpc5Bind in pkt or DceRpc5AlterContext in pkt: 

2572 # bind => get which RPC interface 

2573 for ctx in pkt.context_elem: 

2574 if_uuid = ctx.abstract_syntax.if_uuid 

2575 if_version = ctx.abstract_syntax.if_version 

2576 try: 

2577 self.rpc_bind_interface = DCE_RPC_INTERFACES[(if_uuid, if_version)] 

2578 except KeyError: 

2579 self.rpc_bind_interface = None 

2580 log_runtime.warning( 

2581 "Unknown RPC interface %s. Try loading the IDL" % if_uuid 

2582 ) 

2583 elif DceRpc5BindAck in pkt or DceRpc5AlterContextResp in pkt: 

2584 # bind ack => is it NDR64 

2585 for res in pkt.results: 

2586 if res.result == 0: # Accepted 

2587 self.ndrendian = {0: "big", 1: "little"}[pkt[DceRpc5].endian] 

2588 if res.transfer_syntax.sprintf("%if_uuid%") == "NDR64": 

2589 self.ndr64 = True 

2590 elif DceRpc5Request in pkt: 

2591 # request => match opnum with callID 

2592 opnum = pkt.opnum 

2593 self.map_callid_opnum[pkt.call_id] = opnum, pkt[DceRpc5Request].payload 

2594 elif DceRpc5Response in pkt: 

2595 # response => get opnum from table 

2596 try: 

2597 opnum, opts["request_packet"] = self.map_callid_opnum[pkt.call_id] 

2598 del self.map_callid_opnum[pkt.call_id] 

2599 except KeyError: 

2600 log_runtime.info("Unknown call_id %s in DCE/RPC session" % pkt.call_id) 

2601 # Bind / Alter request/response specific 

2602 if ( 

2603 DceRpc5Bind in pkt 

2604 or DceRpc5AlterContext in pkt 

2605 or DceRpc5BindAck in pkt 

2606 or DceRpc5AlterContextResp in pkt 

2607 ): 

2608 # Detect if "Header Signing" is in use 

2609 if pkt.pfc_flags & 0x04: # PFC_SUPPORT_HEADER_SIGN 

2610 self.header_sign = True 

2611 return opnum, opts 

2612 

2613 # [C706] sect 12.6.2 - Fragmentation and Reassembly 

2614 # Since the connection-oriented transport guarantees sequentiality, the receiver 

2615 # will always receive the fragments in order. 

2616 

2617 def _defragment(self, pkt, body=None): 

2618 """ 

2619 Function to defragment DCE/RPC packets. 

2620 """ 

2621 uid = pkt.call_id 

2622 if pkt.pfc_flags.PFC_FIRST_FRAG and pkt.pfc_flags.PFC_LAST_FRAG: 

2623 # Not fragmented 

2624 return body 

2625 if pkt.pfc_flags.PFC_FIRST_FRAG or uid in self.frags: 

2626 # Packet is fragmented 

2627 if body is None: 

2628 body = pkt[DceRpc5].payload.payload.original 

2629 self.frags[uid] += body 

2630 if pkt.pfc_flags.PFC_LAST_FRAG: 

2631 return self.frags[uid] 

2632 else: 

2633 # Not fragmented 

2634 return body 

2635 

2636 # C706 sect 12.5.2.15 - PDU Body Length 

2637 # "The maximum PDU body size is 65528 bytes." 

2638 MAX_PDU_BODY_SIZE = 4176 

2639 

2640 def _fragment(self, pkt, body): 

2641 """ 

2642 Function to fragment DCE/RPC packets. 

2643 """ 

2644 if len(body) > self.MAX_PDU_BODY_SIZE: 

2645 # Clear any PFC_*_FRAG flag 

2646 pkt.pfc_flags &= 0xFC 

2647 

2648 # Iterate through fragments 

2649 cur = None 

2650 while body: 

2651 # Create a fragment 

2652 pkt_frag = pkt.copy() 

2653 

2654 if cur is None: 

2655 # It's the first one 

2656 pkt_frag.pfc_flags += "PFC_FIRST_FRAG" 

2657 

2658 # Split 

2659 cur, body = ( 

2660 body[: self.MAX_PDU_BODY_SIZE], 

2661 body[self.MAX_PDU_BODY_SIZE :], 

2662 ) 

2663 

2664 if not body: 

2665 # It's the last one 

2666 pkt_frag.pfc_flags += "PFC_LAST_FRAG" 

2667 yield pkt_frag, cur 

2668 else: 

2669 yield pkt, body 

2670 

2671 # [MS-RPCE] sect 3.3.1.5.2.2 

2672 

2673 # The PDU header, PDU body, and sec_trailer MUST be passed in the input message, in 

2674 # this order, to GSS_WrapEx, GSS_UnwrapEx, GSS_GetMICEx, and GSS_VerifyMICEx. For 

2675 # integrity protection the sign flag for that PDU segment MUST be set to TRUE, else 

2676 # it MUST be set to FALSE. For confidentiality protection, the conf_req_flag for 

2677 # that PDU segment MUST be set to TRUE, else it MUST be set to FALSE. 

2678 

2679 # If the authentication level is RPC_C_AUTHN_LEVEL_PKT_PRIVACY, the PDU body will 

2680 # be encrypted. 

2681 # The PDU body from the output message of GSS_UnwrapEx represents the plain text 

2682 # version of the PDU body. The PDU header and sec_trailer output from the output 

2683 # message SHOULD be ignored. 

2684 # Similarly the signature output SHOULD be ignored. 

2685 

2686 def in_pkt(self, pkt): 

2687 # Check for encrypted payloads 

2688 body = None 

2689 if conf.raw_layer in pkt.payload: 

2690 body = bytes(pkt.payload[conf.raw_layer]) 

2691 # If we are doing passive sniffing 

2692 if conf.dcerpc_session_enable and conf.winssps_passive: 

2693 # We have Windows SSPs, and no current context 

2694 if pkt.auth_verifier and pkt.auth_verifier.is_ssp(): 

2695 # This is a bind/alter/auth3 req/resp 

2696 for ssp in self.sniffsspcontexts: 

2697 self.sniffsspcontexts[ssp], status = ssp.GSS_Passive( 

2698 self.sniffsspcontexts[ssp], 

2699 pkt.auth_verifier.auth_value, 

2700 ) 

2701 if status == GSS_S_COMPLETE: 

2702 self.auth_level = DCE_C_AUTHN_LEVEL( 

2703 int(pkt.auth_verifier.auth_level) 

2704 ) 

2705 self.ssp = ssp 

2706 self.sspcontext = self.sniffsspcontexts[ssp] 

2707 self.sniffsspcontexts[ssp] = None 

2708 elif ( 

2709 self.sspcontext 

2710 and pkt.auth_verifier 

2711 and pkt.auth_verifier.is_protected() 

2712 and body 

2713 ): 

2714 # This is a request/response 

2715 if self.sspcontext.passive: 

2716 self.ssp.GSS_Passive_set_Direction( 

2717 self.sspcontext, 

2718 IsAcceptor=DceRpc5Response in pkt, 

2719 ) 

2720 if pkt.auth_verifier and pkt.auth_verifier.is_protected() and body: 

2721 if self.sspcontext is None: 

2722 return pkt 

2723 if self.auth_level in ( 

2724 RPC_C_AUTHN_LEVEL.PKT_INTEGRITY, 

2725 RPC_C_AUTHN_LEVEL.PKT_PRIVACY, 

2726 ): 

2727 # note: 'vt_trailer' is included in the pdu body 

2728 # [MS-RPCE] sect 2.2.2.13 

2729 # "The data structures MUST only appear in a request PDU, and they 

2730 # SHOULD be placed in the PDU immediately after the stub data but 

2731 # before the authentication padding octets. Therefore, for security 

2732 # purposes, the verification trailer is considered part of the PDU 

2733 # body." 

2734 if pkt.vt_trailer: 

2735 body += bytes(pkt.vt_trailer) 

2736 # Account for padding when computing checksum/encryption 

2737 if pkt.auth_padding: 

2738 body += pkt.auth_padding 

2739 

2740 # Build pdu_header and sec_trailer 

2741 pdu_header = pkt.copy() 

2742 sec_trailer = pdu_header.auth_verifier 

2743 # sec_trailer: include the sec_trailer but not the Authentication token 

2744 authval_len = len(sec_trailer.auth_value) 

2745 # Discard everything out of the header 

2746 pdu_header.auth_padding = None 

2747 pdu_header.auth_verifier = None 

2748 pdu_header.payload.payload = NoPayload() 

2749 pdu_header.vt_trailer = None 

2750 

2751 # [MS-RPCE] sect 2.2.2.12 

2752 if self.auth_level == RPC_C_AUTHN_LEVEL.PKT_PRIVACY: 

2753 _msgs = self.ssp.GSS_UnwrapEx( 

2754 self.sspcontext, 

2755 [ 

2756 # "PDU header" 

2757 SSP.WRAP_MSG( 

2758 conf_req_flag=False, 

2759 sign=self.header_sign, 

2760 data=bytes(pdu_header), 

2761 ), 

2762 # "PDU body" 

2763 SSP.WRAP_MSG( 

2764 conf_req_flag=True, 

2765 sign=True, 

2766 data=body, 

2767 ), 

2768 # "sec_trailer" 

2769 SSP.WRAP_MSG( 

2770 conf_req_flag=False, 

2771 sign=self.header_sign, 

2772 data=bytes(sec_trailer)[:-authval_len], 

2773 ), 

2774 ], 

2775 pkt.auth_verifier.auth_value, 

2776 ) 

2777 body = _msgs[1].data # PDU body 

2778 elif self.auth_level == RPC_C_AUTHN_LEVEL.PKT_INTEGRITY: 

2779 self.ssp.GSS_VerifyMICEx( 

2780 self.sspcontext, 

2781 [ 

2782 # "PDU header" 

2783 SSP.MIC_MSG( 

2784 sign=self.header_sign, 

2785 data=bytes(pdu_header), 

2786 ), 

2787 # "PDU body" 

2788 SSP.MIC_MSG( 

2789 sign=True, 

2790 data=body, 

2791 ), 

2792 # "sec_trailer" 

2793 SSP.MIC_MSG( 

2794 sign=self.header_sign, 

2795 data=bytes(sec_trailer)[:-authval_len], 

2796 ), 

2797 ], 

2798 pkt.auth_verifier.auth_value, 

2799 ) 

2800 # Put padding back into the header 

2801 if pkt.auth_padding: 

2802 padlen = len(pkt.auth_padding) 

2803 body, pkt.auth_padding = body[:-padlen], body[-padlen:] 

2804 # Put back vt_trailer into the header, if present. 

2805 if _SECTRAILER_MAGIC in body: 

2806 body, pkt.vt_trailer = pkt.get_field("vt_trailer").getfield( 

2807 pkt, body 

2808 ) 

2809 # If it's a request / response, could be fragmented 

2810 if isinstance(pkt.payload, (DceRpc5Request, DceRpc5Response)) and body: 

2811 body = self._defragment(pkt, body) 

2812 if not body: 

2813 return 

2814 # Get opnum and options 

2815 opnum, opts = self._up_pkt(pkt) 

2816 # Try to parse the payload 

2817 if opnum is not None and self.rpc_bind_interface: 

2818 # use opnum to parse the payload 

2819 is_response = DceRpc5Response in pkt 

2820 try: 

2821 cls = self.rpc_bind_interface.opnums[opnum][is_response] 

2822 except KeyError: 

2823 log_runtime.warning( 

2824 "Unknown opnum %s for interface %s" 

2825 % (opnum, self.rpc_bind_interface) 

2826 ) 

2827 pkt.payload[conf.raw_layer].load = body 

2828 return pkt 

2829 if body: 

2830 # Dissect payload using class 

2831 try: 

2832 payload = cls( 

2833 body, ndr64=self.ndr64, ndrendian=self.ndrendian, **opts 

2834 ) 

2835 except Exception: 

2836 if conf.debug_dissector: 

2837 log_runtime.error("%s dissector failed", cls.__name__) 

2838 if cls is not None: 

2839 raise 

2840 payload = conf.raw_layer(body, _internal=1) 

2841 pkt.payload[conf.raw_layer].underlayer.remove_payload() 

2842 if conf.padding_layer in payload: 

2843 # Most likely, dissection failed. 

2844 log_runtime.warning( 

2845 "Padding detected when dissecting %s. Looks wrong." % cls 

2846 ) 

2847 pad = payload[conf.padding_layer] 

2848 pad.underlayer.payload = conf.raw_layer(load=pad.load) 

2849 pkt /= payload 

2850 # If a request was encrypted, we need to re-register it once re-parsed. 

2851 if not is_response and self.auth_level == RPC_C_AUTHN_LEVEL.PKT_PRIVACY: 

2852 self._up_pkt(pkt) 

2853 elif not cls.fields_desc: 

2854 # Request class has no payload 

2855 pkt /= cls(ndr64=self.ndr64, ndrendian=self.ndrendian, **opts) 

2856 elif body: 

2857 pkt.payload[conf.raw_layer].load = body 

2858 return pkt 

2859 

2860 def out_pkt(self, pkt): 

2861 assert DceRpc5 in pkt 

2862 # Register opnum and options 

2863 self._up_pkt(pkt) 

2864 

2865 # If it's a request / response, we can frag it 

2866 if isinstance(pkt.payload, (DceRpc5Request, DceRpc5Response)): 

2867 # The list of packet responses 

2868 pkts = [] 

2869 # Take the body payload, and eventually split it 

2870 body = bytes(pkt.payload.payload) 

2871 

2872 for pkt, body in self._fragment(pkt, body): 

2873 if pkt.auth_verifier is not None: 

2874 # Verifier already set 

2875 pkts.append(pkt) 

2876 continue 

2877 

2878 # Sign / Encrypt 

2879 if self.sspcontext: 

2880 signature = None 

2881 if self.auth_level in ( 

2882 RPC_C_AUTHN_LEVEL.PKT_INTEGRITY, 

2883 RPC_C_AUTHN_LEVEL.PKT_PRIVACY, 

2884 ): 

2885 # Account for padding when computing checksum/encryption 

2886 if pkt.auth_padding is None: 

2887 padlen = (-len(body)) % _COMMON_AUTH_PAD # authdata padding 

2888 pkt.auth_padding = b"\x00" * padlen 

2889 else: 

2890 padlen = len(pkt.auth_padding) 

2891 # Remember that vt_trailer is included in the PDU 

2892 if pkt.vt_trailer: 

2893 body += bytes(pkt.vt_trailer) 

2894 # Remember that padding IS SIGNED & ENCRYPTED 

2895 body += pkt.auth_padding 

2896 # Add the auth_verifier 

2897 pkt.auth_verifier = CommonAuthVerifier( 

2898 auth_type=self.ssp.auth_type, 

2899 auth_level=self.auth_level, 

2900 auth_context_id=self.auth_context_id, 

2901 auth_pad_length=padlen, 

2902 # Note: auth_value should have the correct length because 

2903 # when using PFC_SUPPORT_HEADER_SIGN, auth_len 

2904 # (and frag_len) is included in the token.. but this 

2905 # creates a dependency loop as you'd need to know the token 

2906 # length to compute the token. Windows solves this by 

2907 # setting the 'Maximum Signature Length' (or something 

2908 # similar) beforehand, instead of the real length. 

2909 # See `gensec_sig_size` in samba. 

2910 auth_value=b"\x00" 

2911 * self.ssp.MaximumSignatureLength(self.sspcontext), 

2912 ) 

2913 # Build pdu_header and sec_trailer 

2914 pdu_header = pkt.copy() 

2915 pdu_header.auth_len = len(pdu_header.auth_verifier) - 8 

2916 pdu_header.frag_len = len(pdu_header) 

2917 sec_trailer = pdu_header.auth_verifier 

2918 # sec_trailer: include the sec_trailer but not the 

2919 # Authentication token 

2920 authval_len = len(sec_trailer.auth_value) 

2921 # sec_trailer.auth_value = None 

2922 # Discard everything out of the header 

2923 pdu_header.auth_padding = None 

2924 pdu_header.auth_verifier = None 

2925 pdu_header.payload.payload = NoPayload() 

2926 pdu_header.vt_trailer = None 

2927 signature = None 

2928 # [MS-RPCE] sect 2.2.2.12 

2929 if self.auth_level == RPC_C_AUTHN_LEVEL.PKT_PRIVACY: 

2930 _msgs, signature = self.ssp.GSS_WrapEx( 

2931 self.sspcontext, 

2932 [ 

2933 # "PDU header" 

2934 SSP.WRAP_MSG( 

2935 conf_req_flag=False, 

2936 sign=self.header_sign, 

2937 data=bytes(pdu_header), 

2938 ), 

2939 # "PDU body" 

2940 SSP.WRAP_MSG( 

2941 conf_req_flag=True, 

2942 sign=True, 

2943 data=body, 

2944 ), 

2945 # "sec_trailer" 

2946 SSP.WRAP_MSG( 

2947 conf_req_flag=False, 

2948 sign=self.header_sign, 

2949 data=bytes(sec_trailer)[:-authval_len], 

2950 ), 

2951 ], 

2952 ) 

2953 s = _msgs[1].data # PDU body 

2954 elif self.auth_level == RPC_C_AUTHN_LEVEL.PKT_INTEGRITY: 

2955 signature = self.ssp.GSS_GetMICEx( 

2956 self.sspcontext, 

2957 [ 

2958 # "PDU header" 

2959 SSP.MIC_MSG( 

2960 sign=self.header_sign, 

2961 data=bytes(pdu_header), 

2962 ), 

2963 # "PDU body" 

2964 SSP.MIC_MSG( 

2965 sign=True, 

2966 data=body, 

2967 ), 

2968 # "sec_trailer" 

2969 SSP.MIC_MSG( 

2970 sign=self.header_sign, 

2971 data=bytes(sec_trailer)[:-authval_len], 

2972 ), 

2973 ], 

2974 pkt.auth_verifier.auth_value, 

2975 ) 

2976 s = body 

2977 else: 

2978 raise ValueError("Impossible") 

2979 # Put padding back in the header 

2980 if padlen: 

2981 s, pkt.auth_padding = s[:-padlen], s[-padlen:] 

2982 # Put back vt_trailer into the header 

2983 if pkt.vt_trailer: 

2984 vtlen = len(pkt.vt_trailer) 

2985 s, pkt.vt_trailer = s[:-vtlen], s[-vtlen:] 

2986 else: 

2987 s = body 

2988 

2989 # now inject the encrypted payload into the packet 

2990 pkt.payload.payload = conf.raw_layer(load=s) 

2991 # and the auth_value 

2992 if signature: 

2993 pkt.auth_verifier.auth_value = signature 

2994 else: 

2995 pkt.auth_verifier = None 

2996 # Add to the list 

2997 pkts.append(pkt) 

2998 return pkts 

2999 else: 

3000 return [pkt] 

3001 

3002 def process(self, pkt: Packet) -> Optional[Packet]: 

3003 """ 

3004 Used when DceRpcSession is used for passive sniffing. 

3005 """ 

3006 pkt = super(DceRpcSession, self).process(pkt) 

3007 if pkt is not None and DceRpc5 in pkt: 

3008 rpkt = self.in_pkt(pkt) 

3009 if rpkt is None: 

3010 # We are passively dissecting a fragmented packet. Return 

3011 # just the header showing that it was indeed, fragmented. 

3012 pkt[DceRpc5].payload.remove_payload() 

3013 return pkt 

3014 return rpkt 

3015 return pkt 

3016 

3017 

3018class DceRpcSocket(StreamSocket): 

3019 """ 

3020 A Wrapper around StreamSocket that uses a DceRpcSession 

3021 """ 

3022 

3023 def __init__(self, *args, **kwargs): 

3024 self.transport = kwargs.pop("transport", None) 

3025 self.session = DceRpcSession( 

3026 ssp=kwargs.pop("ssp", None), 

3027 auth_level=kwargs.pop("auth_level", None), 

3028 auth_context_id=kwargs.pop("auth_context_id", None), 

3029 support_header_signing=kwargs.pop("support_header_signing", True), 

3030 ) 

3031 super(DceRpcSocket, self).__init__(*args, **kwargs) 

3032 

3033 def send(self, x, **kwargs): 

3034 for pkt in self.session.out_pkt(x): 

3035 if self.transport == DCERPC_Transport.NCACN_NP: 

3036 # In this case DceRpcSocket wraps a SMB_RPC_SOCKET, call it directly. 

3037 self.ins.send(pkt, **kwargs) 

3038 else: 

3039 super(DceRpcSocket, self).send(pkt, **kwargs) 

3040 

3041 def recv(self, x=None): 

3042 pkt = super(DceRpcSocket, self).recv(x) 

3043 if pkt is not None: 

3044 return self.session.in_pkt(pkt) 

3045 

3046 

3047# --- TODO cleanup below 

3048 

3049# Heuristically way to find the payload class 

3050# 

3051# To add a possible payload to a DCE/RPC packet, one must first create the 

3052# packet class, then instead of binding layers using bind_layers, he must 

3053# call DceRpcPayload.register_possible_payload() with the payload class as 

3054# parameter. 

3055# 

3056# To be able to decide if the payload class is capable of handling the rest of 

3057# the dissection, the classmethod can_handle() should be implemented in the 

3058# payload class. This method is given the rest of the string to dissect as 

3059# first argument, and the DceRpc packet instance as second argument. Based on 

3060# this information, the method must return True if the class is capable of 

3061# handling the dissection, False otherwise 

3062 

3063 

3064class DceRpc4Payload(Packet): 

3065 """Dummy class which use the dispatch_hook to find the payload class""" 

3066 

3067 _payload_class = [] 

3068 

3069 @classmethod 

3070 def dispatch_hook(cls, _pkt, _underlayer=None, *args, **kargs): 

3071 """dispatch_hook to choose among different registered payloads""" 

3072 for klass in cls._payload_class: 

3073 if hasattr(klass, "can_handle") and klass.can_handle(_pkt, _underlayer): 

3074 return klass 

3075 log_runtime.warning("DCE/RPC payload class not found or undefined (using Raw)") 

3076 return Raw 

3077 

3078 @classmethod 

3079 def register_possible_payload(cls, pay): 

3080 """Method to call from possible DCE/RPC endpoint to register it as 

3081 possible payload""" 

3082 cls._payload_class.append(pay) 

3083 

3084 

3085bind_layers(DceRpc4, DceRpc4Payload)