Exemplo n.º 1
0
class CIP(scapy_all.Packet):
    name = "CIP"
    fields_desc = [
        scapy_all.BitEnumField("direction", None, 1, {
            0: "request",
            1: "response"
        }),
        utils.XBitEnumField(
            "service",
            0,
            7,
            {
                0x01: "Get_Attribute_All",
                0x02: "Set_Attribute_All",
                0x03: "Get_Attribute_List",
                0x04: "Set_Attribute_List",
                0x05: "Reset",
                0x06: "Start",
                0x07: "Stop",
                0x08: "Create",
                0x09: "Delete",
                0x0a: "Multiple_Service_Packet",
                0x0d: "Apply_attributes",
                0x0e: "Get_Attribute_Single",
                0x10: "Set_Attribute_Single",
                0x4b:
                "Execute_PCCC_Service",  # PCCC = Programmable Controller Communication Commands
                0x4c: "Read_Tag_Service",
                0x4d: "Write_Tag_Service",
                0x4e: "Read_Modify_Write_Tag_Service",
                0x4f: "Read_Other_Tag_Service",  # ???
                0x52: "Read_Tag_Fragmented_Service",
                0x53: "Write_Tag_Fragmented_Service",
                0x54: "Forward_Open?",
            }),
        scapy_all.PacketListField("path", [],
                                  CIP_Path,
                                  count_from=lambda p: 1
                                  if p.direction == 0 else 0),
        scapy_all.PacketListField("status", [],
                                  CIP_ResponseStatus,
                                  count_from=lambda p: 1
                                  if p.direction == 1 else 0),
    ]

    def post_build(self, p, pay):
        is_response = (self.direction == 1)
        if self.direction is None and not self.path:
            # Transform the packet into a response
            p = "\x01" + p[1:]
            is_response = True

        if is_response:
            # Add a success status field if there was none
            if not self.status:
                p = p[0:1] + b"\0\0\0" + p[1:]
        return p + pay
Exemplo n.º 2
0
class SCION(scapy.Packet):
    name = 'SCION'
    fields_desc = [
        # Common header
        scapy.BitField('version', 0, 4),
        scapy.BitEnumField('dst_type', "ipv4", 6, SCION_ADDR_TYPE),
        scapy.BitEnumField('src_type', "ipv4", 6, SCION_ADDR_TYPE),
        scapy.BitField('total_len', None, 16),
        scapy.BitField('hdr_len', None, 8),
        scapy.BitField('curr_inf', None, 8),
        scapy.BitField('curr_hf', None, 8),
        scapy.BitEnumField('next_hdr', None, 8, scapy.IP_PROTOS),
        scapy.PacketField('addr', None, SCIONAddr),
        scapy.PacketListField('path',
                              None,
                              PathSegment,
                              count_from=lambda _: 3),
        scapy.PacketField('ext', None, SecurityExtension)
    ]

    # this is terrible, but apparently that's how scapy works :-/
    def post_build(self, pkt, pay):
        # compute lengths
        if self.total_len == None:
            self.total_len = len(pkt) + len(pay)
            pkt = pkt[:2] + struct.pack('!H', self.total_len) + pkt[4:]
        if self.hdr_len == None:
            self.hdr_len = len(pkt) - self.ext.hdr_len
            if self.hdr_len % 8 != 0:
                raise ValueError(
                    "SCION packet header length not multiple of 8 bytes!")
            self.hdr_len = int(self.hdr_len / 8)  #must divide by 8
            pkt = pkt[:4] + struct.pack('B', self.hdr_len) + pkt[5:]

        return pkt + pay
Exemplo n.º 3
0
class PathSegment(scapy.Packet):
    name = 'SCION Path segment'
    fields_desc = [
        scapy.BitField('flags', 0x0, 8),
        UnixTimeField('timestamp', None),
        ISDField('isd', None),
        scapy.FieldLenField('nhops', None, count_of='hops', fmt='B'),
        scapy.PacketListField('hops',
                              None,
                              HopField,
                              count_from=lambda p: p.nhops),
    ]

    def extract_padding(self, p):
        return "", p

    def post_build(self, pkt, pay):
        # compute MACs on HFs
        # this is not a thing that should be done by the client normally :D
        # => only useful for testing
        # TODO This is *not* verified against a "real" SCION packet yet!
        # Somebody should do something!
        def calculate_mac(current, prev):
            if prev != None:
                prev_data = prev[HopField.RANGE_SKIP_FLAGS:HopField.RANGE_END]
            else:
                prev_data = b'\0' * (HopField.RANGE_END -
                                     HopField.RANGE_SKIP_FLAGS)
            data = (
                struct.pack('!I', self.timestamp) + struct.pack(
                    'B', current[HopField.FLAGS] & HopField.IMMUTABLE_FLAGS) +
                current[HopField.RANGE_SKIP_FLAGS:HopField.RANGE_BEFORE_MAC] +
                prev_data)
            # print('prev_data: ', len(prev_data), prev_data.encode('hex'))
            # print('data: ', len(data), data.encode('hex'))
            assert len(data) == 128 // 8

            c = cmac.CMAC(algorithms.AES(HF_MAC_KEY),
                          backend=default_backend())
            c.update(data)
            return c.finalize()

        for i in range(len(self.hops)):
            if not self.hops[i].mac:
                curr_beg = 8 + 8 * i
                curr_end = 8 + 8 * (i + 1)
                prev_beg = curr_beg - 8
                mac_beg = curr_end - 3
                curr = pkt[curr_beg:curr_end]
                prev = pkt[prev_beg:curr_beg] if i > 0 else None
                mac = calculate_mac(curr, prev)

                # print('DEBUG: updating MAC: {} -> {}'.format(struct.pack('!I', self.hops[i].mac).encode('hex'), mac.encode('hex')))
                # print('DEBUG: updating MAC -> {}'.format(mac.encode('hex')))

                mac_bytes = mac[:3]  # take the most significant bits
                pkt = pkt[:mac_beg] + mac_bytes + pkt[curr_end:]

        return pkt + pay
Exemplo n.º 4
0
class ENIP_ListServices(scapy_all.Packet):
    name = "ENIP_ListServices"
    fields_desc = [
        utils.LEShortLenField("count", 1, count_of="TargetItems"),
        scapy_all.PacketListField("TargetItems", [],
                                  ENIP_ListServices_TargetItem,
                                  count_from=lambda p: p.count),
    ]
Exemplo n.º 5
0
class Pixels(scapy.Packet):
    name = "Pixels"
    fields_desc = [
        scapy.ByteField("TypeOfUpdate", 0x00),
        scapy.ByteField("Layer", 0x01),
        scapy.FieldLenField("NumberOfPixelUpdates", None, count_of="PixelData", fmt='H'),
        scapy.PacketListField("PixelData", None, Pixel, count_from=lambda pkt: pkt.NumberOfPixelUpdates)
    ]
Exemplo n.º 6
0
class ENIP_CPF(scapy_all.Packet):
    name = "ENIP_CPF"
    fields_desc = [
        utils.LEShortLenField("count", 2, count_of="items"),
        # Changed implementation to reflect use of CIP_Item above
        scapy_all.PacketListField("items", [],
                                  CPF_Item,
                                  count_from=lambda p: p.count),
        # Due to potential 'optional' packet components at end in protocol
        scapy_all.ConditionalField(
            scapy_all.PacketListField("optional_items",
                                      None,
                                      CPF_Item,
                                      count_from=lambda p: p.count - 2),
            lambda p: p.count > 2),
    ]

    def extract_padding(self, p):
        return '', p
Exemplo n.º 7
0
class ENIP_SendUnitData(scapy_all.Packet):
    """Data in ENIP header specific to the specified command"""
    name = "ENIP_SendUnitData"
    fields_desc = [
        scapy_all.LEIntField("interface_handle", 0),
        scapy_all.LEShortField("timeout", 0),
        utils.LEShortLenField("count", None, count_of="items"),
        scapy_all.PacketListField("items", [],
                                  ENIP_SendUnitData_Item,
                                  count_from=lambda p: p.count),
    ]
Exemplo n.º 8
0
class ENIP_UDP(scapy_all.Packet):
    """Ethernet/IP packet over UDP"""
    name = "ENIP_UDP"
    fields_desc = [
        utils.LEShortLenField("count", None, count_of="items"),
        scapy_all.PacketListField("items", [],
                                  enip_cpf.CPF_Item,
                                  count_from=lambda p: p.count),
    ]

    def extract_padding(self, p):
        return "", p
Exemplo n.º 9
0
class ENIP_ListIdentity(scapy_all.Packet):
    name = "ENIP_ListIdentity"
    fields_desc = [
        utils.LEShortLenField("count", 1, count_of="IdentityItems"),
        scapy_all.PacketListField("IdentityItems", [],
                                  ENIP_ListIdentity_TargetItem,
                                  count_from=lambda p: p.count),
    ]

    def extract_padding(self, p):
        # print self.__class__.__name__ + ": P=" + str(p)
        return "", p
Exemplo n.º 10
0
class ENIP_CPF(scapy_all.Packet):
    name = "ENIP_CPF"
    fields_desc = [
        utils.LEShortLenField("count", 2, count_of="items"),
        scapy_all.PacketListField(
            "items",
            [CPF_AddressDataItem('', 0, 0),
             CPF_AddressDataItem('', 0, 0)],
            CPF_AddressDataItem,
            count_from=lambda p: p.count),
    ]

    def extract_padding(self, p):
        return '', p
Exemplo n.º 11
0
class CIP_ReqForwardOpen(scapy_all.Packet):
    """Forward Open request"""
    name = "CIP_ReqForwardOpen"
    
    SEGMENT_TYPE = {
        0x00: "Port Segment",
        0x01: "Logical Segment",
        0x02: "Network Segment",
        0x03: "Symbolic Segment",
        0x04: "Data Segment",
        0x05: "Data Type (constructed)",
        0x06: "Data Type (elementary)",
        0x07: "Reserved for future use",
    }

    fields_desc = [
        # Updated a few field descriptions to adjust how they are displayed
        # Altered fields begin with utils. rather than scapy_all. - MED
        scapy_all.BitField("priority", 0, 4),
        scapy_all.BitField("tick_time", 0, 4),
        scapy_all.ByteField("timeout_ticks", 249),
        utils.XLEIntField("OT_network_connection_id", 0x80000031),
        utils.XLEIntField("TO_network_connection_id", 0x80fe0030),
        scapy_all.LEShortField("connection_serial_number", 0x1337),
        utils.XLEShortField("vendor_id", 0x004d),
        utils.XLEIntField("originator_serial_number", 0xdeadbeef),
        scapy_all.ByteField("connection_timeout_multiplier", 0),
        scapy_all.X3BytesField("reserved", 0),
        utils.XLEIntField("OT_rpi", 0x007a1200),  # 8000 ms
        scapy_all.PacketField('OT_connection_param', CIP_ConnectionParam(), CIP_ConnectionParam),
        utils.XLEIntField("TO_rpi", 0x007a1200),
        scapy_all.PacketField('TO_connection_param', CIP_ConnectionParam(), CIP_ConnectionParam),
        scapy_all.XByteField("transport_type", 0xa3),  # direction server, application object, class 3
        # Changed  name - MED
        scapy_all.ByteField("Connection_Path_Size", None),  #The number of 16 bit words in the Connection_Path field.
        # scapy_all.PacketListField("path_segment_items", [], CIP_Path1, length_from=lambda p: 2 * p.Connection_Path_Size),
        # Modified Implementation - MED
        scapy_all.PacketListField("path_segment_items", [], CIP_PathPadded, length_from=lambda p: 6),
        # CIP_PathField("path", None, length_from=lambda p: 2 * p.path_wordsize),
    ]