Skip to content
Closed
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
100 changes: 10 additions & 90 deletions scapy/contrib/dce_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@
"""

# TODO: namespace locally used fields
import re
import struct
from scapy.packet import Packet, Raw, bind_layers
from scapy.fields import Field, BitEnumField, ByteEnumField, ByteField, \
FlagsField, IntField, LenField, ShortField, XByteField, XShortField
from scapy.volatile import RandField, RandNum, RandInt, RandShort, RandByte
import scapy.modules.six
from scapy.fields import BitEnumField, ByteEnumField, ByteField, \
FlagsField, IntField, LenField, ShortField, UUIDField, XByteField, \
XShortField


# Fields
Expand All @@ -45,8 +42,13 @@ def set_endianess(self, pkt):
"""Add the endianness to the format"""
end = self.endianess_from(pkt)
if isinstance(end, str) and len(end) > 0:
# fld.fmt should always start with a order specifier, cf field init
self.fld.fmt = end[0] + self.fld.fmt[1:]
if isinstance(self.fld, UUIDField):
self.fld.uuid_fmt = (UUIDField.FORMAT_LE if end == '<'
else UUIDField.FORMAT_BE)
else:
# fld.fmt should always start with a order specifier, cf field
# init
self.fld.fmt = end[0] + self.fld.fmt[1:]

def getfield(self, pkt, buf):
"""retrieve the field with endianness"""
Expand All @@ -62,88 +64,6 @@ def __getattr__(self, attr):
return getattr(self.fld, attr)


class UUIDField(Field):
"""UUID Field"""
__slots__ = ["reg"]

def __init__(self, name, default):
# create and compile the regex used to extract the uuid values from str
reg = r"^\s*{0}-{1}-{1}-{2}{2}-{2}{2}{2}{2}{2}{2}\s*$".format(
"([0-9a-f]{8})", "([0-9a-f]{4})", "([0-9a-f]{2})"
)
self.reg = re.compile(reg, re.I)

Field.__init__(self, name, default, fmt="I2H8B")

def i2m(self, pkt, val):
if val is None:
return (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

if isinstance(val, bytearray) or isinstance(val, str): # py3 concern
# use the regex to extract the values
match = self.reg.match(val)
if match:
# we return a tuple of values after parsing them to integer
return tuple([int(i, 16) for i in match.groups()])
else:
return (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
else:
return val

def m2i(self, pkt, val):
return ("%08x-%04x-%04x-%02x%02x-" + "%02x" * 6) % val

def any2i(self, pkt, val):
if isinstance(val, bytearray) and len(val) == 16:
return self.getfield(pkt, val)[1]
elif isinstance(val, bytearray):
return val.lower()
return val

def addfield(self, pkt, s, val):
return s + struct.pack(self.fmt, *self.i2m(pkt, val))

def getfield(self, pkt, s):
return s[16:], self.m2i(pkt, struct.unpack(self.fmt, s[:16]))

@staticmethod
def randval():
return RandUUID()


class RandUUID(RandField):
"""generate a random UUID"""
def __init__(self, template="*-*-*-**-******"):
base = "([0-9a-f]{{{0}}}|\\*|[0-9a-f]{{{0}}}:[0-9a-f]{{{0}}})"
reg = re.compile(
r"^\s*{0}-{1}-{1}-{2}{2}-{2}{2}{2}{2}{2}{2}\s*$".format(
base.format(8), base.format(4), base.format(2)
),
re.I
)

tmp = reg.match(template)
if tmp:
template = tmp.groups()
else:
template = ["*"] * 11

rnd_f = [RandInt] + [RandShort] * 2 + [RandByte] * 8
self.uuid = ()
for i in scapy.modules.six.moves.range(11):
if template[i] == "*":
val = rnd_f[i]()
elif ":" in template[i]:
mini, maxi = template[i].split(":")
val = RandNum(int(mini, 16), int(maxi, 16))
else:
val = int(template[i], 16)
self.uuid += (val,)

def _fix(self):
return ("%08x-%04x-%04x-%02x%02x-" + "%02x" * 6) % self.uuid


# DCE/RPC Packet
DCE_RPC_TYPE = ["request", "ping", "response", "fault", "working", "no_call",
"reject", "acknowledge", "connectionless_cancel", "frag_ack",
Expand Down
49 changes: 14 additions & 35 deletions scapy/contrib/dce_rpc.uts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
= Import the DCE/RPC layer
import re
from scapy.contrib.dce_rpc import *
from uuid import UUID


+ Check EndiannessField
Expand Down Expand Up @@ -40,46 +41,24 @@ f.getfield(None, '0102030405') == (b'', '0102030405')
f = EndiannessField(StrField('f', 0), lambda p: '>')
f.addfield(None, b'01', '02030405') == b'0102030405'

= Little Endian UUIDField getfield
* The endianness of a UUIDField should be apply by block on each block in
* parenthesis '(01234567)-(89ab)-(cdef)-(01)(23)-(45)(67)(89)(ab)(cd)(ef)'

f = EndiannessField(UUIDField('f', None), lambda p: '<')
f.getfield(None, hex_bytes('0123456789abcdef0123456789abcdef')) == (b'', UUID('67452301-ab89-efcd-0123-456789abcdef'))

+ Check UUIDField

= Parsing a human-readable UUID
f = UUIDField('f', '01234567-89ab-cdef-0123-456789abcdef')
f.addfield(None, b'', f.default) == bytearray.fromhex('0123456789abcdef0123456789abcdef')

= Parsing a machine-encoded UUID
f = UUIDField('f', bytearray.fromhex('0123456789abcdef0123456789abcdef'))
f.addfield(None, b'', f.default) == bytearray.fromhex('0123456789abcdef0123456789abcdef')

= Parsing a tuple of values
f = UUIDField('f', (0x01234567, 0x89ab, 0xcdef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef))
f.addfield(None, b'', f.default) == bytearray.fromhex('0123456789abcdef0123456789abcdef')

= Handle None values
f = UUIDField('f', None)
f.addfield(None, b'', f.default) == bytearray.fromhex('00000000000000000000000000000000')

= Get a UUID for dissection
f = UUIDField('f', None)
f.getfield(None, bytearray.fromhex('0123456789abcdef0123456789abcdef01')) == (b'\x01', '01234567-89ab-cdef-0123-456789abcdef')

= Verify little endianness of UUIDField
* The endianness of a UUIDField should be apply by block on each block in parenthesis '(01234567)-(89ab)-(cdef)-(01)(23)-(45)(67)(89)(ab)(cd)(ef)'
= Little Endian UUIDField addfield
f = EndiannessField(UUIDField('f', '01234567-89ab-cdef-0123-456789abcdef'), lambda p: '<')
f.addfield(None, b'', f.default) == bytearray.fromhex('67452301ab89efcd0123456789abcdef')

= Verify RandUUID
re.match(r'[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}', str(RandUUID()), re.I) is not None

= Verify RandUUID with a static part
* RandUUID template can contain static part such a 01234567-89ab-*-01*-*****ef
re.match(r'01234567-89ab-[0-9a-f]{4}-01[0-9a-f]{2}-[0-9a-f]{10}ef', str(RandUUID('01234567-89ab-*-01*-*****ef')), re.I) is not None
f.addfield(None, b'', f.default) == hex_bytes('67452301ab89efcd0123456789abcdef')

= Verify RandUUID with a range part
* RandUUID template can contain a part with a range of values such a 01234567-89ab-*-01*-****c0:c9ef
re.match(r'01234567-89ab-[0-9a-f]{4}-01[0-9a-f]{2}-[0-9a-f]{8}c[0-9]ef', str(RandUUID('01234567-89ab-*-01*-****c0:c9ef')), re.I) is not None
= Big Endian UUIDField getfield
f = EndiannessField(UUIDField('f', None), lambda p: '>')
f.getfield(None, hex_bytes('0123456789abcdef0123456789abcdef')) == (b'', UUID('01234567-89ab-cdef-0123456789abcdef'))

= Big Endian UUIDField addfield
f = EndiannessField(UUIDField('f', '01234567-89ab-cdef-0123-456789abcdef'), lambda p: '>')
f.addfield(None, b'', f.default) == hex_bytes('0123456789abcdef0123456789abcdef')


+ Check DCE/RPC layer
Expand Down
79 changes: 13 additions & 66 deletions scapy/contrib/opc_da.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,13 @@
Using the website: https://msdn.microsoft.com/en-us/library/cc226801.aspx
"""

import uuid

from scapy.compat import plain_str
from scapy.config import conf
from scapy.fields import Field, ByteField, ShortField, LEShortField, \
IntField, LEIntField, LongField, LELongField, StrField, StrLenField, \
StrFixedLenField, BitEnumField, ByteEnumField, ShortEnumField, \
LEShortEnumField, IntEnumField, LEIntEnumField, FieldLenField, \
LEFieldLenField, PacketField, PacketListField, PacketLenField, \
ConditionalField, FlagsField
ConditionalField, FlagsField, UUIDField
from scapy.packet import Packet

# Defined values
Expand Down Expand Up @@ -271,58 +268,6 @@ def extract_padding(self, p):
return b"", p


class PUUID(Field):
__slots__ = ["endianType"]

def __init__(self, name, default, endianType):
_repr = {0: 'bigEndian', 1: 'littleEndian'}
Field.__init__(self, name, default, "16s")
self.endianType = _repr[endianType]

def h2i(self, pkt, x):
""" Description: transform a string uuid in uuid type object """
self.default = uuid.UUID(plain_str(x or ""))
return self.default

def i2h(self, pkt, x):
""" Description: transform a type uuid object in string uuid """
x = str(self.default)
return x

def m2i(self, pkt, x):
""" Description: transform a byte string uuid in uuid type object """
if self.endianType == 'bigEndian':
self.default = uuid.UUID(bytes=x)
elif self.endianType == 'littleEndian':
self.default = uuid.UUID(bytes_le=x)
return self.default

def i2m(self, pkt, x):
""" Description: transform a uuid type object in a byte string """
if self.endianType == 'bigEndian':
x = self.default.bytes
elif self.endianType == 'littleEndian':
x = self.default.bytes_le
return x

def i2repr(self, pkt, x):
return str(self.default)

def getfield(self, pkt, s):
""" Extract an internal value from a string """
self.default = self.m2i(pkt, s[:self.sz])
return s[self.sz:], self.default

def addfield(self, pkt, s, val):
""" Add an internal value to a string """
return s + self.i2m(pkt, val)

def any2i(self, pkt, x):
""" Try to understand the most input values possible and make an
internal value from them """
return self.h2i(pkt, x)


class LenStringPacket(Packet):
name = "len string packet"
fields_desc = [
Expand Down Expand Up @@ -358,7 +303,8 @@ def extract_padding(self, p):
class SyntaxId(Packet):
name = "syntax Id"
fields_desc = [
PUUID('interfaceUUID', str('0001' * 8), 0),
UUIDField('interfaceUUID', str('0001' * 8),
uuid_fmt=UUIDField.FORMAT_BE),
ShortField('versionMajor', 0),
ShortField('versionMinor', 0),
]
Expand All @@ -370,7 +316,8 @@ def extract_padding(self, p):
class SyntaxIdLE(Packet):
name = "syntax Id"
fields_desc = [
PUUID('interfaceUUID', str('0001' * 8), 1),
UUIDField('interfaceUUID', str('0001' * 8),
uuid_fmt=UUIDField.FORMAT_LE),
LEShortField('versionMajor', 0),
LEShortField('versionMinor', 0),
]
Expand Down Expand Up @@ -471,7 +418,7 @@ class STDOBJREF(Packet):
LEIntField('cPublicRefs', 0),
LELongField('OXID', 0),
LELongField('OID', 0),
PacketField('IPID', None, PUUID),
PacketField('IPID', None, UUIDField),
]


Expand Down Expand Up @@ -524,7 +471,7 @@ class OBJREF_HANDLER(Packet):
name = "objetref stanDard"
fields_desc = [
PacketField('std', None, STDOBJREF),
PUUID('clsid', str('0001' * 8), 0),
UUIDField('clsid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_BE),
PacketField('saResAddr', None, DualStringArray),
]

Expand All @@ -533,15 +480,15 @@ class OBJREF_HANDLERLE(Packet):
name = "objetref stanDard"
fields_desc = [
PacketField('std', None, STDOBJREF),
PUUID('clsid', str('0001' * 8), 1),
UUIDField('clsid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_LE),
PacketField('saResAddr', None, DualStringArrayLE),
]


class OBJREF_CUSTOM(Packet):
name = "objetref stanDard"
fields_desc = [
PUUID('clsid', str('0001' * 8), 0),
UUIDField('clsid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_BE),
IntField('cbExtension', 0),
IntField('reserved', 0),
]
Expand All @@ -550,7 +497,7 @@ class OBJREF_CUSTOM(Packet):
class OBJREF_CUSTOMLE(Packet):
name = "objetref stanDard"
fields_desc = [
PUUID('clsid', str('0001' * 8), 1),
UUIDField('clsid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_LE),
LEIntField('cbExtension', 0),
LEIntField('reserved', 0),
]
Expand Down Expand Up @@ -946,7 +893,7 @@ class RequestSubDataLE(Packet):
LEShortField('versionMinor', 0),
LEIntField('flags', 0),
LEIntField('reserved', 0),
PUUID('subUuid', str('0001' * 8), 1),
UUIDField('subUuid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_LE),
StrField('subdata', ''),
]

Expand All @@ -960,7 +907,7 @@ class OpcDaRequest(Packet):
IntField('allocHint', 0),
ShortField('contextId', 0),
ShortField('opNum', 0),
PUUID('uuid', str('0001' * 8), 0),
UUIDField('uuid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_BE),
PacketLenField('subData', None, RequestSubData,
length_from=lambda pkt:pkt.allocHint),
PacketField('authentication', None, AuthentificationProtocol),
Expand All @@ -976,7 +923,7 @@ class OpcDaRequestLE(Packet):
LEIntField('allocHint', 0),
LEShortField('contextId', 0),
LEShortField('opNum', 0),
PUUID('uuid', str('0001' * 8), 1),
UUIDField('uuid', str('0001' * 8), uuid_fmt=UUIDField.FORMAT_LE),
PacketLenField('subData', None, RequestSubDataLE,
length_from=lambda pkt:pkt.allocHint),
PacketField('authentication', None, AuthentificationProtocol),
Expand Down
Loading