-
Notifications
You must be signed in to change notification settings - Fork 60
umap documentation
umap is a tool which allows you to test the security of USB host implementations i.e. something you plug a USB device into, like a PC or a tablet. Its primary function at the moment is a fuzzer with test cases based on a combination of data from standards documentation and the author's experience of where USB bugs are commonly found. However, it also has additional functionality that will be expanded further in future versions, for example:
- Operating system identification
- Installed application identification
- Vendor-specific driver enumeration
- Endpoint Protection System assessment
umap requires a Facedancer board to enable devices to be virtualised in Python and presented to the target host. The firmware and basic Facedancer demo software can be downloaded here.
umap is written in Python so to run it just type:
$ sudo python3 umap.py
(umap must be run as root)
--------------------------------------- _ _ _ __ ___ __ _ _ __ | | | | '_ ` _ \ / _` | '_ \ | |_| | | | | | | (_| | |_) | \__,_|_| |_| |_|\__,_| .__/ |_| The USB host assessment tool Andy Davis, NCC Group 2013 Version: 1.01 Based on Facedancer by Travis Goodspeed For help type: umap.py -h --------------------------------------- Error: Facedancer serial port not supplied
As you can see, it complains that you haven't supplied the serial port to which the Facedancer is connected. By typing umap.py -h you can see how to do this:
Usage: umap.py Options: --version show program's version number and exit -h, --help show this help message and exit -P SERIAL Facedancer serial port **Mandatory option** (SERIAL=/dev/ttyX or just 1 for COM1) -L List device classes supported by umap -i identify all supported device classes on connected host -c CLS identify if a specific class on the connected host is supported (CLS=class:subclass:proto) -O Operating system identification -e DEVICE emulate a specific device (DEVICE=class:subclass:proto) -v VID specify Vendor ID (hex format e.g. 1a2b) -p PID specify Product ID (hex format e.g. 1a2b) -r REV specify product Revision (hex format e.g. 1a2b) -f FUZZC fuzz a specific class (FUZZC=class:subclass:proto:E/C/A[:start fuzzcase]) -s FUZZS send a single fuzz testcase (FUZZS=class:subclass:proto:E/C:Testcase) -d DLY delay between enumeration attempts (seconds): Default=1 -l LOG log to a file -R REF Reference the VID/PID database (REF=VID:PID) -u update the VID/PID database (Internet connectivity required) Experimental Options: -A APPLE emulate an Apple iPhone device (APPLE=VID:PID:REV) -b VENDOR brute-force vendor driver support (VENDOR=VID:PID)
The only mandatory option is -P to provide the serial port that the Facedancer board is connected to e.g.
$ sudo python3 umap.py -P /dev/ttyUSB0
In order to fuzz a USB host you need to emulate the process of physical insertion and removal of your virtual device. The USB design is expecting this process to be performed by a human and therefore, attempting to perform the operation too quickly results in the host getting confused (...but that a whole different area of potential research). As a result, USB fuzzing can be very slow (7-10 seconds per fuzz test case) so it's very important to be able to enumerate what classes of USB device are supported by the host before you start fuzzing.
To display which device classes umap can emulate use the -L option, which results in something like this:
XX:YY:ZZ - XX = Class : YY = Subclass : ZZ = Protocol 01:01:00 - Audio : Audio control : PR Protocol undefined 01:02:00 - Audio : Audio streaming : PR Protocol undefined 02:02:01 - CDC Control : Abstract Control Model : AT commands V.250 02:03:ff - CDC Control : Telephone Control Model : Vendor specific 02:06:00 - CDC Control : Ethernet Networking Control Model : No class-specific protocol required 03:00:00 - Human Interface Device : No subclass : None 06:01:01 - Image : Still image capture device : Bulk-only protocol 07:01:02 - Printer : Default : Bidirectional interface 08:06:50 - Mass Storage : SCSI : BBB 09:00:00 - Hub : Default : Default 0a:00:00 - CDC Data : Default : Default 0b:00:00 - Smart Card : Default : Default
As you can see, USB class information is represented by three bytes, the first being the base class e.g. 08 = Mass Storage class, the second is the sub-class e.g. 06 = SCSI (for Mass Storage) and the third is the protocol e.g. BBB (for Mass Storage).
In order to identify which of these virtual devices is supported by the USB host that your are testing, use the following command:
$ sudo python3 umap.py -P /dev/ttyUSB0 -i 01:01:00 - Audio : Audio control : PR Protocol undefined **SUPPORTED** 01:02:00 - Audio : Audio streaming : PR Protocol undefined **SUPPORTED** 02:02:01 - CDC Control : Abstract Control Model : AT commands V.250 02:03:ff - CDC Control : Telephone Control Model : Vendor specific 02:06:00 - CDC Control : Ethernet Networking Control Model : No class-specific protocol required 03:00:00 - Human Interface Device : No subclass : None **SUPPORTED** 06:01:01 - Image : Still image capture device : Bulk-only protocol **SUPPORTED** 07:01:02 - Printer : Default : Bidirectional interface 08:06:50 - Mass Storage : SCSI : BBB **SUPPORTED** 09:00:00 - Hub : Default : Default **SUPPORTED** 0a:00:00 - CDC Data : Default : Default **SUPPORTED** 0b:00:00 - Smart Card : Default : Default
The output above shows that the Audio device class is supported, but CDC is not. The -c option allows you to test if specific device classes are supported by the host rather than cycling through all of them.
Now that we know what classes are supported we can emulate a device and virtually connect it to the USB target host. Below is output of umap emulating a Still image capture device connected to an Ubuntu Linux host, which concluded with Linux starting the Shotwell application and displaying an image that is stored on the virtual USB camera device:
$ sudo python3 umap.py -P /dev/ttyUSB0 -e 06:01:01 Emulating 06:01:01 - Image : Still image capture device : Bulk-only protocol Facedancer reset GoodFET monitor initialized MAXUSB initialized MAXUSB enabled MAXUSB revision 19 MAXUSB connected device USB image device USB image device received request dir=1, type=0, rec=0, r=6, v=256, i=0, l=64 USB image device received GET_DESCRIPTOR req 1, index 0, language 0x0000, length 64 MAXUSB wrote 12 01 00 02 00 00 00 40 da 04 74 23 10 00 01 02 03 01 to endpoint 0 USB image device received request dir=0, type=0, rec=0, r=5, v=15, i=0, l=0 USB image device received SET_ADDRESS request for address 15 USB image device received request dir=1, type=0, rec=0, r=6, v=256, i=0, l=18 USB image device received GET_DESCRIPTOR req 1, index 0, language 0x0000, length 18 MAXUSB wrote 12 01 00 02 00 00 00 40 da 04 74 23 10 00 01 02 03 01 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=1536, i=0, l=10 USB image device received GET_DESCRIPTOR req 6, index 0, language 0x0000, length 10 MAXUSB wrote 0a 06 00 02 00 00 00 40 01 00 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=512, i=0, l=9 USB image device received GET_DESCRIPTOR req 2, index 0, language 0x0000, length 9 MAXUSB wrote 09 02 27 00 01 01 04 e0 32 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=512, i=0, l=39 USB image device received GET_DESCRIPTOR req 2, index 0, language 0x0000, length 39 MAXUSB wrote 09 02 27 00 01 01 04 e0 32 09 04 00 00 03 06 01 01 00 07 05 01 02 40 00 00 07 05 82 02 40 00 00 07 05 83 03 08 00 10 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=768, i=0, l=255 USB image device received GET_DESCRIPTOR req 3, index 0, language 0x0000, length 255 MAXUSB wrote 04 03 09 04 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=770, i=1033, l=255 USB image device received GET_DESCRIPTOR req 3, index 2, language 0x0409, length 255 MAXUSB wrote 10 03 44 00 4d 00 43 00 2d 00 46 00 53 00 37 00 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=769, i=1033, l=255 USB image device received GET_DESCRIPTOR req 3, index 1, language 0x0409, length 255 MAXUSB wrote 14 03 50 00 61 00 6e 00 61 00 73 00 6f 00 6e 00 69 00 63 00 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=771, i=1033, l=255 USB image device received GET_DESCRIPTOR req 3, index 3, language 0x0409, length 255 MAXUSB wrote 3e 03 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 31 00 58 00 30 00 32 00 30 00 39 00 30 00 33 00 30 00 37 00 35 00 34 00 to endpoint 0 USB image device received request dir=0, type=0, rec=0, r=9, v=1, i=0, l=0 USB image device received SET_CONFIGURATION request USB image device received request dir=1, type=0, rec=0, r=6, v=772, i=1033, l=255 USB image device received GET_DESCRIPTOR req 3, index 4, language 0x0409, length 255 MAXUSB wrote 0c 03 49 00 6d 00 61 00 67 00 65 00 to endpoint 0 USB image interface handling 16 bytes of Image class data USB image interface got OpenSession USB image interface sent Image:OK USB image interface responding with 12 bytes: 0c 00 00 00 03 00 01 20 00 00 00 00 USB image interface handling 12 bytes of Image class data USB image interface got GetDeviceInfo USB image interface sent Image:OK USB image interface responding with 211 bytes: d3 00 00 00 02 00 01 10 01 00 00 00 64 00 06 00 00 00 64 00 00 00 00 10 00 00 00 01 10 02 10 03 10 04 10 05 10 06 10 07 10 08 10 09 10 0a 10 0c 10 0d 10 14 10 15 10 16 10 1b 10 04 00 00 00 04 40 05 40 08 40 09 40 02 00 00 00 06 d4 07 d4 00 00 00 00 06 00 00 00 01 30 02 30 06 30 0d 30 01 38 0d 38 0a 50 00 61 00 6e 00 61 00 73 00 6f 00 6e 00 69 00 63 00 00 00 08 44 00 4d 00 43 00 2d 00 46 00 53 00 37 00 00 00 04 31 00 2e 00 30 00 00 00 20 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 31 00 58 00 30 00 32 00 30 00 39 00 30 00 33 00 30 00 37 00 35 00 34 00 00 00 00 00 USB image interface responding with 12 bytes: 0c 00 00 00 03 00 01 20 01 00 00 00 USB image interface handling 12 bytes of Image class data USB image interface got GetStorageIDs USB image interface sent Image:OK USB image interface responding with 20 bytes: 14 00 00 00 02 00 04 10 02 00 00 00 01 00 00 00 01 00 01 00 USB image interface responding with 12 bytes: 0c 00 00 00 03 00 01 20 02 00 00 00 USB image interface handling 16 bytes of Image class data USB image interface got GetStorageInfo USB image interface sent Image:OK USB image interface responding with 40 bytes: 28 00 00 00 02 00 05 10 03 00 00 00 04 00 03 00 00 00 00 00 18 78 00 00 00 00 00 80 da 77 00 00 00 00 00 00 00 00 00 00 --truncated for brevity--
Specific USB devices are identified by three 16-bit numbers: Vendor ID (VID), Product ID (PID) and Revision number (Rev - although this is often not used and just left as zero). This information is registered with and maintained by the USB Implementers Forum. If you wish to emulate a specific device of a certain class you can specify the VID, PID and REV using the -v, -p and -r options respectively. Furthermore, umap maintains a local copy of the VID/PID/REV database and lookups can be performed using the -R option (the local copy can be updated with -u). An example is shown below:
$ sudo python3 umap.py -P /dev/ttyUSB0 -R 04da:2374 Looking up VID= 04da / PID= 2374 Panasonic (Matsushita) Lumix Camera (PTP mode) $ sudo python3 umap.py -P /dev/ttyUSB0 -e 06:01:01 -v 04da -p 2374 -r 0000 VID = 04da PID = 2374 REV = 0000 Emulating 06:01:01 - Image : Still image capture device : Bulk-only protocol Facedancer reset GoodFET monitor initialized MAXUSB initialized MAXUSB enabled MAXUSB revision 0 MAXUSB connected device USB image device USB image device received request dir=1, type=0, rec=0, r=6, v=256, i=0, l=64 USB image device received GET_DESCRIPTOR req 1, index 0, language 0x0000, length 64 MAXUSB wrote 12 01 00 02 00 00 00 40 da 04 74 23 00 00 01 02 03 01 to endpoint 0 USB image device received request dir=0, type=0, rec=0, r=5, v=16, i=0, l=0 USB image device received SET_ADDRESS request for address 16 USB image device received request dir=1, type=0, rec=0, r=6, v=256, i=0, l=18 USB image device received GET_DESCRIPTOR req 1, index 0, language 0x0000, length 18 MAXUSB wrote 12 01 00 02 00 00 00 40 da 04 74 23 00 00 01 02 03 01 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=1536, i=0, l=10 USB image device received GET_DESCRIPTOR req 6, index 0, language 0x0000, length 10 MAXUSB wrote 0a 06 00 02 00 00 00 40 01 00 to endpoint 0 USB image device received request dir=1, type=0, rec=0, r=6, v=512, i=0, l=9 USB image device received GET_DESCRIPTOR req 2, index 0, language 0x0000, length 9 MAXUSB wrote 09 02 27 00 01 01 04 e0 32 to endpoint 0 --truncated for brevity--
umap can perform simple operating system identification (this will be extended in future versions of the tool) using the -O option. More information about techniques that can be used to identify operating systems and applications via USB can be found in the Revealing Embedded Fingerprints white paper. An example is shown below:
$ sudo python3 umap.py -P /dev/ttyUSB0 -O Fingerprinting the connected host - please wait... OS Matches: Apple iPad/iPhone
The primary function of umap is fuzzing so if you wish to fuzz a specific device class on the target host you can use either the -f (fuzz) or -s (single-shot) options. The class information is provided as usual, but you also need to specify if you want to fuzz just the enumeration phase ('E'), just the class-specific test cases ('C') or everything ('A'). In single-shot mode you then need to provide the test case number to use and if a test case number if provided in fuzz mode, the fuzzer will start at the specified test case. Examples are shown below (note that in both modes umap first performs a test to confirm that the device class is supported by the target):
$ sudo python3 umap.py -P /dev/ttyUSB0 -s 01:01:00:E:6 Fuzzing: 01:01:00 - Audio : Audio control : PR Protocol undefined **SUPPORTED** 2013/10/10 15:35:26 Enumeration phase: 0006 - Device_bMaxPacketSize0_null $
$ sudo python3 umap.py -P /dev/ttyUSB0 -f 01:01:00:C Fuzzing: 01:01:00 - Audio : Audio control : PR Protocol undefined **SUPPORTED** Class-specific data... 2013/10/10 15:38:04 Audio class: 0000 - CSInterface1_wTotalLength_null 2013/10/10 15:38:15 Audio class: 0001 - CSInterface1_wTotalLength_lower 2013/10/10 15:38:26 Audio class: 0002 - CSInterface1_wTotalLength_higher 2013/10/10 15:38:37 Audio class: 0003 - CSInterface1_wTotalLength_max 2013/10/10 15:38:47 Audio class: 0004 - CSInterface1_baInterfaceNr1_null *** No response from host - check if the host is still functioning correctly *** $
In the second example above, the target crashed as a result of the fourth test case (CSInterface1_wTotalLength_max), as there is no response to the fifth test case that was sent. The test cases are stored in testcases.py and therefore can easily be changed or added to.
The output can be logged to a file using the -l option:
-l LOG log to a file
It's highly unlikely you'll need this option, but if you wish to add a delay between test cases then the -d option can be used:
-d DLY delay between enumeration attempts (seconds): Default=1
umap isn't perfect - there are a number of known issues:
- The Facedancer hardware is slow compared to "real" USB devices so don't expect performance to be anywhere near what you would expect from actual devices
- If you stop umap by pressing 'Ctrl' c it may leave the Facedancer board in an indeterminate state, which means that next time the tool is run it may not communicate properly with the target. If this happens the easiest way to fix it is to unplug and then re-insert the Facedancer board (at the computer running umap)