Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 51 additions & 7 deletions scapy/layers/dcerpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1943,9 +1943,19 @@ class NDRPacketField(NDRConstructedType, NDRAlign):
def __init__(self, name, default, pkt_cls, **kwargs):
self.DEPORTED_CONFORMANTS = pkt_cls.DEPORTED_CONFORMANTS
self.fld = _NDRPacketField(name, default, pkt_cls=pkt_cls, **kwargs)

# The inner _NDRPacketPadField handles NDR64's trailing gap in
# the case where there a no inner conformants (see [MS-RPCE] 2.2.5.3.4.1)
if self.DEPORTED_CONFORMANTS:
innerfld = self.fld
else:
innerfld = _NDRPacketPadField(self.fld, align=pkt_cls.ALIGNMENT)

# C706 14.3.2 Alignment of Constructed Types is handled by the
# NDRAlign below.
NDRAlign.__init__(
self,
_NDRPacketPadField(self.fld, align=pkt_cls.ALIGNMENT),
innerfld,
align=pkt_cls.ALIGNMENT,
)
NDRConstructedType.__init__(self, pkt_cls.fields_desc)
Expand Down Expand Up @@ -1996,11 +2006,12 @@ class _NDRPacketListField(NDRConstructedType, PacketListField):
islist = 1
holds_packets = 1

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

def __init__(self, name, default, pkt_cls, **kwargs):
self.ptr_pack = kwargs.pop("ptr_pack", False)
if self.ptr_pack:
self.ptr_lvl = kwargs.pop("ptr_lvl", False)
if self.ptr_lvl:
# TODO: support more than 1 level ?
self.fld = NDRFullEmbPointerField(NDRPacketField("", None, pkt_cls))
else:
self.fld = NDRPacketField("", None, pkt_cls)
Expand Down Expand Up @@ -2042,7 +2053,6 @@ class NDRFieldListField(NDRConstructedType, FieldListField):
islist = 1

def __init__(self, *args, **kwargs):
kwargs.pop("ptr_pack", None) # TODO: unimplemented
if "length_is" in kwargs:
kwargs["count_from"] = kwargs.pop("length_is")
elif "size_is" in kwargs:
Expand Down Expand Up @@ -2098,6 +2108,9 @@ def __init__(self, *args, **kwargs):
kwargs["length_from"] = length_is
elif self.COUNT_FROM:
kwargs["count_from"] = length_is
# TODO: For now, we do nothing with max_is
if "max_is" in kwargs:
kwargs.pop("max_is")
super(_NDRVarField, self).__init__(*args, **kwargs)

def getfield(self, pkt, s):
Expand Down Expand Up @@ -2221,13 +2234,23 @@ def __init__(self, *args, **kwargs):
kwargs["length_from"] = size_is
elif self.COUNT_FROM:
kwargs["count_from"] = size_is
# TODO: For now, we do nothing with max_is
if "max_is" in kwargs:
kwargs.pop("max_is")
super(_NDRConfField, self).__init__(*args, **kwargs)

def getfield(self, pkt, s):
# [C706] - 14.3.7 Structures Containing Arrays
fmt = _e(pkt.ndrendian) + ["I", "Q"][pkt.ndr64]
if self.conformant_in_struct:
return super(_NDRConfField, self).getfield(pkt, s)
# [MS-RPCE] 2.2.5.3.4.2 Structure Containing a Conformant Array
# Padding is here: just before the Conformant content
return NDRAlign(
super(_NDRConfField, self),
align=pkt.ALIGNMENT,
).getfield(pkt, s)

# The max count is aligned as a primitive type
remain, max_count = NDRAlign(Field("", 0, fmt=fmt), align=(4, 8)).getfield(
pkt, s
)
Expand All @@ -2238,7 +2261,12 @@ def getfield(self, pkt, s):

def addfield(self, pkt, s, val):
if self.conformant_in_struct:
return super(_NDRConfField, self).addfield(pkt, s, val)
# [MS-RPCE] 2.2.5.3.4.2 Structure Containing a Conformant Array
# Padding is here: just before the Conformant content
return NDRAlign(super(_NDRConfField, self), align=pkt.ALIGNMENT).addfield(
pkt, s, val
)

if self.CONFORMANT_STRING and not isinstance(val, NDRConformantString):
raise ValueError(
"Expected NDRConformantString in %s. You are using it wrong!"
Expand Down Expand Up @@ -2385,6 +2413,22 @@ class NDRConfStrLenFieldUtf16(_NDRConfField, _NDRValueOf, StrLenFieldUtf16, _NDR
LENGTH_FROM = True


class NDRVarStrNullField(_NDRVarField, _NDRValueOf, StrNullField):
"""
NDR Varying StrNullField
"""

NULLFIELD = True


class NDRVarStrNullFieldUtf16(_NDRVarField, _NDRValueOf, StrNullFieldUtf16, _NDRUtf16):
"""
NDR Varying StrNullFieldUtf16
"""

NULLFIELD = True


class NDRVarStrLenField(_NDRVarField, StrLenField):
"""
NDR Varying StrLenField
Expand Down
2 changes: 1 addition & 1 deletion scapy/layers/msrpce/msdcom.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class PropsOutInfo(NDRPacket):
[],
MInterfacePointer,
size_is=lambda pkt: pkt.cIfs,
ptr_pack=True,
ptr_lvl=1,
)
),
]
Expand Down
118 changes: 105 additions & 13 deletions scapy/layers/msrpce/raw/ept.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# See https://scapy.net/ for more information
# Copyright (C) Gabriel Potter

# ept.idl compiled on 06/07/2025
# This file is a stripped version ! Use scapy-rpc for the full.
# This is from [MS-RPCE] and [C706] Appendix O

"""
RPC definitions for the following interfaces:
- ept (v3.0): e1af8308-5d1f-11c9-91a4-08002b14a0fa
Expand All @@ -17,6 +17,8 @@
from scapy.layers.dcerpc import (
NDRPacket,
DceRpcOp,
NDRByteField,
NDRConfPacketListField,
NDRConfStrLenField,
NDRConfVarPacketListField,
NDRContextHandle,
Expand All @@ -40,17 +42,8 @@ class UUID(NDRPacket):
]


class RPC_IF_ID(NDRPacket):
ALIGNMENT = (4, 4)
fields_desc = [
NDRPacketField("Uuid", UUID(), UUID),
NDRShortField("VersMajor", 0),
NDRShortField("VersMinor", 0),
]


class twr_p_t(NDRPacket):
ALIGNMENT = (4, 8)
ALIGNMENT = (4, 4)
DEPORTED_CONFORMANTS = ["tower_octet_string"]
fields_desc = [
NDRIntField("tower_length", None, size_of="tower_octet_string"),
Expand All @@ -72,6 +65,42 @@ class ept_entry_t(NDRPacket):
]


class ept_insert_Request(NDRPacket):
fields_desc = [
NDRIntField("num_ents", None, size_of="entries"),
NDRConfPacketListField(
"entries", [], ept_entry_t, size_is=lambda pkt: pkt.num_ents
),
NDRIntField("replace", 0),
]


class ept_insert_Response(NDRPacket):
fields_desc = [NDRIntField("status", 0)]


class ept_delete_Request(NDRPacket):
fields_desc = [
NDRIntField("num_ents", None, size_of="entries"),
NDRConfPacketListField(
"entries", [], ept_entry_t, size_is=lambda pkt: pkt.num_ents
),
]


class ept_delete_Response(NDRPacket):
fields_desc = [NDRIntField("status", 0)]


class RPC_IF_ID(NDRPacket):
ALIGNMENT = (4, 4)
fields_desc = [
NDRPacketField("Uuid", UUID(), UUID),
NDRShortField("VersMajor", 0),
NDRShortField("VersMinor", 0),
]


class ept_lookup_Request(NDRPacket):
fields_desc = [
NDRIntField("inquiry_type", 0),
Expand Down Expand Up @@ -117,15 +146,78 @@ class ept_map_Response(NDRPacket):
twr_p_t,
size_is=lambda pkt: pkt.max_towers,
length_is=lambda pkt: pkt.num_towers,
ptr_pack=True,
ptr_lvl=1,
),
NDRIntField("status", 0),
]


class ept_lookup_handle_free_Request(NDRPacket):
fields_desc = [NDRPacketField("entry_handle", NDRContextHandle(), NDRContextHandle)]


class ept_lookup_handle_free_Response(NDRPacket):
fields_desc = [
NDRPacketField("entry_handle", NDRContextHandle(), NDRContextHandle),
NDRIntField("status", 0),
]


class uuid_t(NDRPacket):
ALIGNMENT = (4, 4)
fields_desc = [
NDRIntField("time_low", 0),
NDRShortField("time_mid", 0),
NDRShortField("time_hi_and_version", 0),
NDRByteField("clock_seq_hi_and_reserved", 0),
NDRByteField("clock_seq_low", 0),
StrFixedLenField("node", "", length=6),
]


class ept_inq_object_Request(NDRPacket):
fields_desc = []


class ept_inq_object_Response(NDRPacket):
fields_desc = [
NDRPacketField("ept_object", uuid_t(), uuid_t),
NDRIntField("status", 0),
]


class uuid_p_t(NDRPacket):
ALIGNMENT = (4, 4)
fields_desc = [
NDRIntField("time_low", 0),
NDRShortField("time_mid", 0),
NDRShortField("time_hi_and_version", 0),
NDRByteField("clock_seq_hi_and_reserved", 0),
NDRByteField("clock_seq_low", 0),
StrFixedLenField("node", "", length=6),
]


class ept_mgmt_delete_Request(NDRPacket):
fields_desc = [
NDRIntField("object_speced", 0),
NDRPacketField("object", uuid_p_t(), uuid_p_t),
NDRPacketField("tower", twr_p_t(), twr_p_t),
]


class ept_mgmt_delete_Response(NDRPacket):
fields_desc = [NDRIntField("status", 0)]


EPT_OPNUMS = {
0: DceRpcOp(ept_insert_Request, ept_insert_Response),
1: DceRpcOp(ept_delete_Request, ept_delete_Response),
2: DceRpcOp(ept_lookup_Request, ept_lookup_Response),
3: DceRpcOp(ept_map_Request, ept_map_Response),
4: DceRpcOp(ept_lookup_handle_free_Request, ept_lookup_handle_free_Response),
5: DceRpcOp(ept_inq_object_Request, ept_inq_object_Response),
6: DceRpcOp(ept_mgmt_delete_Request, ept_mgmt_delete_Response),
}
register_dcerpc_interface(
name="ept",
Expand Down
20 changes: 12 additions & 8 deletions scapy/layers/msrpce/raw/ms_dcom.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class GUID(NDRPacket):


class ORPC_EXTENT(NDRPacket):
ALIGNMENT = (4, 8)
ALIGNMENT = (4, 4)
DEPORTED_CONFORMANTS = ["data"]
fields_desc = [
NDRPacketField("id", GUID(), GUID),
Expand All @@ -89,7 +89,7 @@ class ORPC_EXTENT_ARRAY(NDRPacket):
[],
ORPC_EXTENT,
size_is=lambda pkt: ((pkt.size + 1) & (~1)),
ptr_pack=True,
ptr_lvl=1,
)
),
]
Expand All @@ -109,7 +109,7 @@ class ORPCTHIS(NDRPacket):


class MInterfacePointer(NDRPacket):
ALIGNMENT = (4, 8)
ALIGNMENT = (4, 4)
DEPORTED_CONFORMANTS = ["abData"]
fields_desc = [
NDRIntField("ulCntData", None, size_of="abData"),
Expand All @@ -130,7 +130,7 @@ class ORPCTHAT(NDRPacket):


class DUALSTRINGARRAY(NDRPacket):
ALIGNMENT = (4, 8)
ALIGNMENT = (2, 2)
DEPORTED_CONFORMANTS = ["aStringArray"]
fields_desc = [
NDRShortField("wNumEntries", None, size_of="aStringArray"),
Expand All @@ -155,7 +155,11 @@ class RemoteActivation_Request(NDRPacket):
NDRIntField("ClientImpLevel", 0),
NDRIntField("Mode", 0),
NDRIntField("Interfaces", None, size_of="pIIDs"),
NDRConfPacketListField("pIIDs", [], GUID, size_is=lambda pkt: pkt.Interfaces),
NDRFullPointerField(
NDRConfPacketListField(
"pIIDs", [], GUID, size_is=lambda pkt: pkt.Interfaces
)
),
NDRShortField("cRequestedProtseqs", None, size_of="aRequestedProtseqs"),
NDRConfFieldListField(
"aRequestedProtseqs",
Expand All @@ -182,7 +186,7 @@ class RemoteActivation_Response(NDRPacket):
[],
MInterfacePointer,
size_is=lambda pkt: pkt.Interfaces,
ptr_pack=True,
ptr_lvl=1,
),
NDRConfFieldListField(
"pResults", [], NDRSignedIntField("", 0), size_is=lambda pkt: pkt.Interfaces
Expand Down Expand Up @@ -414,7 +418,7 @@ class RemQueryInterface_Request(NDRPacket):
class RemQueryInterface_Response(NDRPacket):
fields_desc = [
NDRConfPacketListField(
"ppQIResults", [], REMQIRESULT, size_is=lambda pkt: pkt.cIids, ptr_pack=True
"ppQIResults", [], REMQIRESULT, size_is=lambda pkt: pkt.cIids, ptr_lvl=1
),
NDRIntField("status", 0),
]
Expand Down Expand Up @@ -491,7 +495,7 @@ class RemQueryInterface2_Response(NDRPacket):
"phr", [], NDRSignedIntField("", 0), size_is=lambda pkt: pkt.cIids
),
NDRConfPacketListField(
"ppMIF", [], MInterfacePointer, size_is=lambda pkt: pkt.cIids, ptr_pack=True
"ppMIF", [], MInterfacePointer, size_is=lambda pkt: pkt.cIids, ptr_lvl=1
),
NDRIntField("status", 0),
]
Expand Down
7 changes: 3 additions & 4 deletions scapy/layers/msrpce/raw/ms_nrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# See https://scapy.net/ for more information
# Copyright (C) Gabriel Potter

# [ms-nrpc] v45.0 (Tue, 08 Jul 2025)
# [ms-nrpc] v49.0 (Mon, 09 Feb 2026)

"""
RPC definitions for the following interfaces:
Expand Down Expand Up @@ -301,7 +301,6 @@ class RPC_SID_IDENTIFIER_AUTHORITY(NDRPacket):


class PRPC_SID(NDRPacket):
ALIGNMENT = (4, 8)
DEPORTED_CONFORMANTS = ["SubAuthority"]
fields_desc = [
NDRByteField("Revision", 0),
Expand Down Expand Up @@ -3556,7 +3555,7 @@ class DsrDeregisterDnsHostRecords_Request(NDRPacket):
NDRFullPointerField(NDRConfVarStrNullFieldUtf16("DnsDomainName", "")),
NDRFullPointerField(NDRPacketField("DomainGuid", GUID(), GUID)),
NDRFullPointerField(NDRPacketField("DsaGuid", GUID(), GUID)),
NDRConfVarStrNullFieldUtf16("DnsHostName", ""),
NDRFullPointerField(NDRConfVarStrNullFieldUtf16("DnsHostName", "")),
]


Expand Down Expand Up @@ -3692,7 +3691,7 @@ class PLSA_FOREST_TRUST_INFORMATION(NDRPacket):
[],
PLSA_FOREST_TRUST_RECORD,
size_is=lambda pkt: pkt.RecordCount,
ptr_pack=True,
ptr_lvl=1,
)
),
]
Expand Down
Loading
Loading