Pico 2017: Just Keyp Trying

Overview

As with the previous examples, we are given a pcap that, upon opening, we discover contains USB packets. This example will go over a trick that may be necessary when you do not have all the packets. Specifically, it discusses how to handle the case when we do not have all the descriptors present but still want to parse out the keystrokes.

Step 0: Analysis

To start with, let’s open the pcap with gallimaufry:

In [1]: from Gallimaufry.USB import USB

In [2]: pcap = USB("./data.pcap")

In [3]: pcap
Out[3]: <USB packets=66>

This example is a very clean pcap. Only 66 packets! Let’s see what packets we’ve found by looking at the summary:

In [5]: print(pcap.summary)
PCAP:
data.pcap
Total Packets: 66

Devices
-------

Here is where you find the gotcha. The summary returned nothing! The reason for this is that, upon inspection of the pcap, the USB descriptor payloads are not present. Due to this, gallimaufry does not know the types of objects to create.

If you wanted to inspect the packets parsed through gallimaufry manually, you can use the pcap property:

In [6]: pcap.pcap
OrderedDict([('_index', 'packets-2017-10-25'),
              ('_type', 'pcap_file'),
              ('_score', None),
              ('_source',
               OrderedDict([('layers',
                             OrderedDict([('frame',
                                           OrderedDict([('frame.encap_type',
                                                         '152'),
                                                        ('frame.time',
                                                         'Mar 22, 2017 21:07:40.230170000 EDT'),
                                                        ('frame.offset_shift',
                                                         '0.000000000'),
                                                        ('frame.time_epoch',
                                                         '1490231260.230170000'),
                                                        ('frame.time_delta',
                                                         '3.716062000'),
                                                        ('frame.time_delta_displayed',
                                                         '3.716062000'),
                                                        ('frame.time_relative',
                                                         '23.453109000'),
                                                        ('frame.number', '65'),
                                                        ('frame.len', '35'),
                                                        ('frame.cap_len',
                                                         '35'),
                                                        ('frame.marked', '0'),
                                                        ('frame.ignored', '0'),
                                                        ('frame.protocols',
                                                         'usb')])),
                                          ('usb',
                                           OrderedDict([('usb.src', '2.1.1'),
                                                        ('usb.addr', 'host'),
                                                        ('usb.dst', 'host'),
                                                        ('usb.usbpcap_header_len',
                                                         '27'),
                                                        ('usb.irp_id',
                                                         '0xffffb689ac2d3940'),
                                                        ('usb.usbd_status',
                                                         '0'),
                                                        ('usb.function', '9'),
                                                        ('usb.irp_info',
                                                         '0x00000001'),
                                                        ('usb.irp_info_tree',
                                                         OrderedDict([('usb.irp_info.reserved',
                                                                       '0x00000000'),
                                                                      ('usb.irp_info.direction',
                                                                       '0x00000001')])),
                                                        ('usb.bus_id', '2'),
                                                        ('usb.device_address',
                                                         '1'),
                                                    ('usb.endpoint_number',
                                                     '0x00000081'),
                                                    ('usb.endpoint_number_tree',
                                                     OrderedDict([('usb.endpoint_number.direction',
                                                                   '1'),
                                                                  ('usb.endpoint_number.endpoint',
                                                                   '1')])),
                                                    ('usb.transfer_type',
                                                     '0x00000001'),
                                                    ('usb.data_len', '8'),
                                                    ('usb.bInterfaceClass',
                                                     '65535')])),
                                      ('usb.capdata',
                                       '01:00:00:00:00:00:00:00')]))]))]),
                                       <<clipped>>

Future work on this tool will include endpoint summaries that are agnostic of Devices, but until that time you will have to do a bit of manual work to pull out the packets you’re interested in.

Step 1: Extract the Keystrokes

Since we were not able to auto-parse this pcap, we will need to first extract the relevant packets. To do this, let’s pull out all packets with the USB endpoint of 1 on bus_id 2 and device_address 1

Note

Remember that the actual endpoint number is derived from the endpoint_number field (in this case 0x81) by taking the lowest 3 bits. Here, we have 0x81 & 0b111 == 1.

In [7]: packets = pcap.pcap_filter(bus_id=2, device_address=1, endpoint_number=1)

In [8]: len(packets)
Out [8]: 66

Note here that the number of packets we extracted is the same as the total number of packets this capture has. The authors of this challenge were trying to be nice to us by removing unnecessary payloads before giving it to us.

At this point, we would like to parse out the keystrokes. However, the Keyboard object wasn’t automatically generated for us. Since we have the packets we want, let’s manually generate a Keyboard object with these packets:

In [9]: from Gallimaufry.Classes.HID.Keyboard import Keyboard

In [10]: keyboard = Keyboard(packets)

In [11]: keyboard
Out [11]: <Keyboard keystrokes=29>

Our Keyboard object has been created, and it successfully parsed out 29 keystrokes from the packets it received. We can now ask it to print out those keystrokes as we have done previously:

In [12]: keyboard.keystrokes
Out [12]: 'flag{pr355_0nwards_c98ccf99}[LEFT_CONTROL]c'

Funny enough, we also caught the authors executing a Ctrl-C using the Left Control button.

Resources