def GenerateHidReport(report_str, name=None): ''' Generate an HID report Container from a HID report string :param report_str: HID report string :param name: name of generated Container (default: None) :raises: KittyException if not enough bytes are left for command :examples: :: Template( name='MyHidReport', fields=GenerateHidReport( '05010906A101050719E029E7150025017501950881029501750881011900296515002565750895018100C0', ) ) ''' fields = [] index = 0 namer = NameGen() while index < len(report_str): opcode = report_str[index] num_args = opcode & 3 if index + num_args >= len(report_str): raise KittyException('Not enough bytes in hid report for last opcode') index += 1 cur_name = namer.gen(opcode) if num_args == 0: fields.append(UInt8(opcode, name=cur_name)) else: args = report_str[index:index + num_args] value = sum(args[i] << (i * 8) for i in range(len(args))) # little endian... fields.append(Container( name=cur_name, fields=[ UInt8(opcode, name='opcode'), BitField(value, 8 * len(args), encoder=ENC_INT_LE, name='value') ] )) index += num_args return OneOf( name=name, fields=[ Container( name='generation', fields=fields ), MutableField( name='mutation', value=report_str ), RandomHidReport( name='random_sequences' ), ])
def __init__(self, name, status, error, chain_param, ab_data, fuzzable=True): fields = [ UInt8(name='bMessageType', value=0x80), SizeInBytes(name='dwLength', sized_field=ab_data, length=32, fuzzable=True, encoder=ENC_INT_LE), DynamicInt(name='bSlot', key='bSlot', bitfield=UInt8(name='bSlotInt', value=0)), DynamicInt(name='bSeq', key='bSeq', bitfield=UInt8(name='bSeqInt', value=0)), UInt8(name='bStatus', value=status), UInt8(name='bError', value=error), UInt8(name='bChainParameter', value=chain_param), Container(name='abData', fields=ab_data), ] super(R2PDataBlock, self).__init__(name=name, fields=fields, fuzzable=fuzzable)
def __init__(self, name, descriptor_type, fields, fuzz_type=True): if isinstance(fields, BaseField): fields = [fields] fields.insert( 0, SizeInBytes(name='bLength', sized_field=self, length=8, fuzzable=True)) fields.insert( 1, UInt8(name='bDescriptorType', value=descriptor_type, fuzzable=fuzz_type)) super(SubDescriptor, self).__init__(name=name, fields=fields)
def __init__(self, name, status, error, clock_status, fuzzable=True): fields = [ UInt8(name='bMessageType', value=0x80), LE32(name='dwLength', value=0x00), DynamicInt(name='bSlot', key='bSlot', bitfield=UInt8(name='bSlotInt', value=0)), DynamicInt(name='bSeq', key='bSeq', bitfield=UInt8(name='bSeqInt', value=0)), UInt8(name='bStatus', value=status), UInt8(name='bError', value=error), UInt8(name='bClockStatus', value=clock_status), ] super(R2PSlotStatus, self).__init__(name=name, fields=fields, fuzzable=fuzzable)
index += num_args return OneOf(name=name, fields=[ Container(name='generation', fields=fields), MutableField(name='mutation', value=report_str), RandomHidReport(name='random_sequences'), ]) # ############### Templates ############### # hid_descriptor = Descriptor(name='hid_descriptor', descriptor_type=DescriptorType.hid, fields=[ DynamicInt('bcdHID', LE16(value=0x0110)), DynamicInt('bCountryCode', UInt8(value=0x00)), DynamicInt('bNumDescriptors', UInt8(value=0x01)), DynamicInt('bDescriptorType2', UInt8(value=DescriptorType.hid)), DynamicInt('wDescriptorLength', LE16(value=0x27)), ]) # this descriptor is based on umap # https://github.com/nccgroup/umap # commit 3ad812135f8c34dcde0e055d1fefe30500196c0f hid_report_descriptor = Template( name='hid_report_descriptor', fields=GenerateHidReport( '05010906A101050719E029E7150025017501950881029501750881011900296515002565750895018100C0'
'''Descriptor sub types [audio10.pdf table A-6]''' AS_DESCRIPTOR_UNDEFINED = 0x00 AS_GENERAL = 0x01 FORMAT_TYPE = 0x02 FORMAT_SPECIFIC = 0x03 # TODO: audio_ep2_buffer_available # TODO: remove? audio_header_descriptor = Descriptor( name='audio_header_descriptor', descriptor_type=_DescriptorTypes.CS_INTERFACE, fields=[ UInt8(name='bDesciptorSubType', value=_AC_DescriptorSubTypes.HEADER), LE16(name='bcdADC', value=0x0100), LE16(name='wTotalLength', value=0x1e), UInt8(name='bInCollection', value=0x1), Repeat(UInt8(name='baInterfaceNrX', value=1), 0, 247) ]) # TODO: remove? audio_input_terminal_descriptor = Descriptor( descriptor_type=_DescriptorTypes.CS_INTERFACE, name='audio_input_terminal_descriptor', fields=[ UInt8(name='bDesciptorSubType', value=_AC_DescriptorSubTypes.INPUT_TERMINAL), UInt8(name='bTerminalID', value=0x00), LE16(name='wTerminalType', value=0x0206), # termt10.pdf table 2-2
DescriptorType.hub, self.num_ports, self.hub_chars, self.pwr_on_2_pwr_good, self.hub_contr_current, ) num_bytes = self.num_ports // 7 if self.num_ports % 7 != 0: num_bytes += 1 d += b'\x00' * num_bytes d += b'\xff' * num_bytes d = struct.pack('B', len(d) + 1) + d return d ''' hub_descriptor = Descriptor(name='hub_descriptor', descriptor_type=DescriptorType.hub, fields=[ Size(name='bNbrPorts', sized_field='DeviceRemovable', length=8, calc_func=lambda x: len(x) * 7), LE16(name='wHubCharacteristics', value=0x0000), UInt8(name='bPwrOn2PwrGood', value=0x00), UInt8(name='bHubContrCurrent', value=0x02), RandomBytes(name='DeviceRemovable', value=b'\x00', min_length=0, max_length=250), ])
from kitty.model import SizeInBytes from numap.fuzz.templates.generic import SizedPt # TODO: scsi_test_unit_ready_response (nothing to fuzz! no data returned, besides the csw) # TODO: scsi_send_diagnostic_response # TODO: scsi_prevent_allow_medium_removal_response # TODO: scsi_write_10_response (nothing to fuzz! no data returned, besides the csw) # TODO: scsi_write_6_response # TODO: scsi_read_6_response # TODO: scsi_verify_10_response # USBMassStorageClass msc_get_max_lun_response = Template( name='msc_get_max_lun_response', fields=UInt8(name='Max_LUN', value=0x00)) # Request Sense - FuzzableUSBMassStorageInterface scsi_request_sense_response = Template( name='scsi_request_sense_response', fields=[ UInt8(name='ResponseCode', value=0x70), UInt8(name='VALID', value=0x00), UInt8(name='Obsolete', value=0x00), UInt8(name='SenseKey', value=0x00), UInt8(name='Resv', value=0x00), UInt8(name='ILI', value=0x00), UInt8(name='EOM', value=0x00), UInt8(name='FILEMARK', value=0x00), BE32(name='Information', value=0x00),
from numap.dev.cdc import FunctionalDescriptor, CommunicationClassSubclassCodes from numap.core.usb_class import USBClass from numap.core.usb import DescriptorType from kitty.model import UInt8, LE16, RandomBytes, BitField, Static from kitty.model import Template, Repeat, List, Container, ForEach, OneOf from kitty.model import ElementCount from kitty.model import MutableField from numap.fuzz.templates.generic import SubDescriptor cdc_control_interface_descriptor = Template( name='cdc_control_interface_descriptor', fields=[ SubDescriptor(name='Standard interface descriptor', descriptor_type=DescriptorType.interface, fields=[ UInt8(name='bInterfaceNumber', value=0x00), UInt8(name='bAlternateSetting', value=0x00), ElementCount(name='bNumEndpoints', depends_on='endpoints', length=8), UInt8(name='bInterfaceClass', value=USBClass.CDC, fuzzable=False), UInt8(name='bInterfaceSubClass', value=CommunicationClassSubclassCodes.Reserved, fuzzable=False), UInt8(name='bInterfaceProtocol', value=0x00), UInt8(name='iInterface', value=0x01), ]), List( name='Class-Specific interfaces',
USB_TERMINAL = 9 NETWORK_CHANNEL_TERMINAL = 0xa PROTOCOL_UNIT = 0xb EXTENSION_UNIT = 0xc MULTI_CHANNEL_MANAGEMENT = 0xd CAPI_CONTROL_MANAGEMENT = 0xe ETHERNET_NETWORKING = 0xf ATM_NETWORKING = 0x10 # 0x11-0xff reserved cdc_header_functional_descriptor = Descriptor( name='cdc_header_functional_descriptor', descriptor_type=_DescriptorTypes.CS_INTERFACE, fields=[ UInt8(name='bDesciptorSubType', value=_CDC_DescriptorSubTypes.HEADER_FUNCTIONAL), LE16(name='bcdCDC', value=0xffff) ]) cdc_call_management_functional_descriptor = Descriptor( name='cdc_call_management_functional_descriptor', descriptor_type=_DescriptorTypes.CS_INTERFACE, fields=[ UInt8(name='bDesciptorSubType', value=_CDC_DescriptorSubTypes.CALL_MANAGMENT), BitField(name='bmCapabilities', value=0, length=8), UInt8(name='bDataInterface', value=0) ]) # TODO: Missing descriptors for subtypes 3,4,5
# dynamic fields from kitty.model import ElementCount, SizeInBytes # encoders from kitty.model import StrEncodeEncoder, ENC_INT_LE from generic import Descriptor, SubDescriptor # Device descriptor # Section 9.6.1, page 261 device_descriptor = Descriptor( name='device_descriptor', descriptor_type=DescriptorType.device, fields=[ LE16( name='bcdUSB', value=0x0100 ), # USB 2.0 is reported as 0x0200, USB 1.1 as 0x0110 and USB 1.0 as 0x0100 UInt8(name='bDeviceClass', value=0), UInt8(name='bDeviceSubClass', value=0), UInt8(name='bDeviceProtocol', value=0), UInt8(name='bMaxPacketSize', value=64), # valid sizes: 8,16,32,64 LE16(name='idVendor', value=0), LE16(name='idProduct', value=0), LE16(name='bcdDevice', value=0), UInt8(name='iManufacturer', value=0), UInt8(name='iProduct', value=0), UInt8(name='iSerialNumber', value=0), UInt8(name='bNumConfigurations', value=0) ]) # Device qualifier descriptor # Section 9.6.2, page 264 device_qualifier_descriptor = Descriptor(