diff --git a/scapy/layers/dcerpc.py b/scapy/layers/dcerpc.py index 7174e59993b..39ea79a0636 100644 --- a/scapy/layers/dcerpc.py +++ b/scapy/layers/dcerpc.py @@ -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) @@ -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) @@ -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: @@ -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): @@ -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 ) @@ -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!" @@ -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 diff --git a/scapy/layers/msrpce/msdcom.py b/scapy/layers/msrpce/msdcom.py index cc4208acc4a..a6cadfe5008 100644 --- a/scapy/layers/msrpce/msdcom.py +++ b/scapy/layers/msrpce/msdcom.py @@ -358,7 +358,7 @@ class PropsOutInfo(NDRPacket): [], MInterfacePointer, size_is=lambda pkt: pkt.cIfs, - ptr_pack=True, + ptr_lvl=1, ) ), ] diff --git a/scapy/layers/msrpce/raw/ept.py b/scapy/layers/msrpce/raw/ept.py index 9a3f3b60271..33c0cde4984 100644 --- a/scapy/layers/msrpce/raw/ept.py +++ b/scapy/layers/msrpce/raw/ept.py @@ -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 @@ -17,6 +17,8 @@ from scapy.layers.dcerpc import ( NDRPacket, DceRpcOp, + NDRByteField, + NDRConfPacketListField, NDRConfStrLenField, NDRConfVarPacketListField, NDRContextHandle, @@ -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"), @@ -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), @@ -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", diff --git a/scapy/layers/msrpce/raw/ms_dcom.py b/scapy/layers/msrpce/raw/ms_dcom.py index 33240f3601e..5dede93fc20 100644 --- a/scapy/layers/msrpce/raw/ms_dcom.py +++ b/scapy/layers/msrpce/raw/ms_dcom.py @@ -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), @@ -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, ) ), ] @@ -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"), @@ -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"), @@ -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", @@ -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 @@ -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), ] @@ -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), ] diff --git a/scapy/layers/msrpce/raw/ms_nrpc.py b/scapy/layers/msrpce/raw/ms_nrpc.py index 0772469ba4b..0b51a063d67 100644 --- a/scapy/layers/msrpce/raw/ms_nrpc.py +++ b/scapy/layers/msrpce/raw/ms_nrpc.py @@ -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: @@ -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), @@ -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", "")), ] @@ -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, ) ), ] diff --git a/scapy/layers/msrpce/rpcclient.py b/scapy/layers/msrpce/rpcclient.py index e3a1d46a435..8afe70ad55e 100644 --- a/scapy/layers/msrpce/rpcclient.py +++ b/scapy/layers/msrpce/rpcclient.py @@ -169,6 +169,7 @@ def connect( :param timeout: (optional) the connection timeout (default 5) :param port: (optional) the port to connect to. (useful for SMB) """ + smb_kwargs.setdefault("HOST", host) if endpoint is None and interface is not None: # Figure out the endpoint using the endpoint mapper diff --git a/scapy/tools/UTscapy.py b/scapy/tools/UTscapy.py index bd703869e74..b4761c5b8fc 100644 --- a/scapy/tools/UTscapy.py +++ b/scapy/tools/UTscapy.py @@ -323,6 +323,7 @@ def parse_config_file(config_path, verb=3): "local": true, "format": "ansi", "num": null, + "extensions": [], "modules": [], "kw_ok": [], "kw_ko": [] @@ -349,6 +350,7 @@ def get_if_exist(key, default): local=get_if_exist("local", False), num=get_if_exist("num", None), modules=get_if_exist("modules", []), + extensions=get_if_exist("extensions", []), kw_ok=get_if_exist("kw_ok", []), kw_ko=get_if_exist("kw_ko", []), format=get_if_exist("format", "ansi")) @@ -996,6 +998,7 @@ def main(): GLOB_PREEXEC = "" PREEXEC_DICT = {} MODULES = [] + EXTENSIONS = [] TESTFILES = [] ANNOTATIONS_MODE = False INTERPRETER = False @@ -1048,6 +1051,7 @@ def main(): LOCAL = 1 if data.local else 0 NUM = data.num MODULES = data.modules + EXTENSIONS = data.extensions KW_OK.extend(data.kw_ok) KW_KO.extend(data.kw_ko) try: @@ -1138,6 +1142,9 @@ def main(): except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (m, e)) + for ext in EXTENSIONS: + conf.exts.load(ext) + autorun_func = { Format.TEXT: scapy.autorun_get_text_interactive_session, Format.ANSI: scapy.autorun_get_ansi_interactive_session, diff --git a/test/configs/bsd.utsc b/test/configs/bsd.utsc index 912a4f7c210..583a27cc0ef 100644 --- a/test/configs/bsd.utsc +++ b/test/configs/bsd.utsc @@ -2,6 +2,8 @@ "testfiles": [ "test/*.uts", "test/scapy/layers/*.uts", + "test/scapy/layers/tls/*.uts", + "test/scapy/layers/msrpce/*.uts", "test/contrib/automotive/*.uts", "test/contrib/automotive/obd/*.uts", "test/contrib/automotive/scanner/*.uts", @@ -25,7 +27,7 @@ "test/contrib/*.uts": "load_contrib(\"%name%\")", "test/cert.uts": "load_layer(\"tls\")", "test/sslv2.uts": "load_layer(\"tls\")", - "test/tls*.uts": "load_layer(\"tls\")" + "test/scapy/layers/tls/*.uts": "load_layer(\"tls\")" }, "kw_ko": [ "linux", diff --git a/test/configs/cryptography.utsc b/test/configs/cryptography.utsc index 4963fc71438..8408f9fdb2b 100644 --- a/test/configs/cryptography.utsc +++ b/test/configs/cryptography.utsc @@ -5,7 +5,7 @@ "test/scapy/layers/ipsec.uts", "test/scapy/layers/kerberos.uts", "test/scapy/layers/ntlm.uts", - "test/scapy/layers/msnrpc.uts", + "test/scapy/layers/msrpce/msnrpc.uts", "test/scapy/layers/tls/cert.uts", "test/scapy/layers/tls/tls*.uts" ], diff --git a/test/configs/linux.utsc b/test/configs/linux.utsc index 25fbb6bd1d6..7972e1e8739 100644 --- a/test/configs/linux.utsc +++ b/test/configs/linux.utsc @@ -3,6 +3,7 @@ "test/*.uts", "test/scapy/layers/*.uts", "test/scapy/layers/tls/*.uts", + "test/scapy/layers/msrpce/*.uts", "test/contrib/*.uts", "test/tools/*.uts", "test/contrib/automotive/*.uts", diff --git a/test/configs/scapy-rpc.utsc b/test/configs/scapy-rpc.utsc new file mode 100644 index 00000000000..1d600b2b7b6 --- /dev/null +++ b/test/configs/scapy-rpc.utsc @@ -0,0 +1,9 @@ +{ + "testfiles": [ + "test/scapy/layers/dcerpc.uts", + "test/scapy/layers/msrpce/*.uts" + ], + "extensions": ["scapy-rpc"], + "breakfailed": true, + "onlyfailed": true +} diff --git a/test/configs/windows.utsc b/test/configs/windows.utsc index 468979a5ca5..2e015eb24e9 100644 --- a/test/configs/windows.utsc +++ b/test/configs/windows.utsc @@ -3,6 +3,7 @@ "test\\*.uts", "test\\scapy\\layers\\*.uts", "test\\scapy\\layers\\tls\\*.uts", + "test\\scapy\\layers\\msrpce\\*.uts", "test\\contrib\\automotive\\obd\\*.uts", "test\\contrib\\automotive\\scanner\\*.uts", "test\\contrib\\automotive\\gm\\*.uts", diff --git a/test/configs/windows2.utsc b/test/configs/windows2.utsc index a1c8e302953..de1fe81d9ed 100644 --- a/test/configs/windows2.utsc +++ b/test/configs/windows2.utsc @@ -3,6 +3,7 @@ "*.uts", "scapy\\layers\\*.uts", "scapy\\layers\\tls\\*.uts", + "scapy\\layers\\msrpce\\*.uts", "contrib\\automotive\\obd\\*.uts", "contrib\\automotive\\gm\\*.uts", "contrib\\automotive\\bmw\\*.uts", diff --git a/test/scapy/layers/msdrsr.uts b/test/scapy/layers/msrpce/msdrsr.uts similarity index 100% rename from test/scapy/layers/msdrsr.uts rename to test/scapy/layers/msrpce/msdrsr.uts diff --git a/test/scapy/layers/msrpce/mslsad.uts b/test/scapy/layers/msrpce/mslsad.uts new file mode 100644 index 00000000000..195f539dd44 --- /dev/null +++ b/test/scapy/layers/msrpce/mslsad.uts @@ -0,0 +1,38 @@ +% MS-LSAD tests + ++ [MS-LSAD] build and dissection tests + +* This files are stored in the scapy-rpc extension, but included as part of Scapy's main testing suite for consistency. + += [MS-LSAD] - Import [MS-LSAD] +~ disabled + +from scapy.layers.msrpce.raw.ms_lsad import * + += [MS-LSAD] - Build LsarEnumerateAccountsWithUserRight_Request +~ disabled + +policyHandle = NDRContextHandle(attributes=0, uuid=b'\x92\xa1*"\xc2\xc2\nJ\xaf\x0bL\xdd]C\x8c\x1a') +right = "SeAuditPrivilege" + +pkt = LsarEnumerateAccountsWithUserRight_Request( + PolicyHandle=policyHandle, + UserRight=PRPC_UNICODE_STRING( + Buffer=right, + ), +) + +assert bytes(pkt) == b'\x00\x00\x00\x00\x92\xa1*"\xc2\xc2\nJ\xaf\x0bL\xdd]C\x8c\x1a\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00S\x00e\x00A\x00u\x00d\x00i\x00t\x00P\x00r\x00i\x00v\x00i\x00l\x00e\x00g\x00e\x00' + += [MS-LSAD] - Dissect LsarEnumerateAccountsWithUserRight_Response +~ disabled + +from scapy.layers.smb2 import WINNT_SID + +pkt = LsarEnumerateAccountsWithUserRight_Response(b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\t\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x05 \x00\x00\x00*\x02\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x05 \x00\x00\x00 \x02\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00') +information = pkt.valueof("EnumerationBuffer.Information") +assert [ + WINNT_SID(bytes(x.valueof("Sid"))).summary() + for x in information +] == ['S-1-5-9', 'S-1-5-32-554', 'S-1-5-32-544', 'S-1-5-11', 'S-1-1-0'] + diff --git a/test/scapy/layers/msnrpc.uts b/test/scapy/layers/msrpce/msnrpc.uts similarity index 100% rename from test/scapy/layers/msnrpc.uts rename to test/scapy/layers/msrpce/msnrpc.uts diff --git a/tox.ini b/tox.ini index c3a06ac726a..a013a8b9807 100644 --- a/tox.ini +++ b/tox.ini @@ -33,6 +33,7 @@ deps = cryptography coverage[toml] python-can + scapy-rpc # disabled on windows because they require c++ dependencies # brotli 1.1.0 broken https://github.com/google/brotli/issues/1072 brotli < 1.1.0 ; sys_platform != 'win32'