Tuesday, February 18, 2014

Bluetooth Recon With BlueZ

Bluetooth devices are all around us and a surprising number of them are left discoverable. In this post I describe techniques for finding discoverable Bluetooth devices and listing the services running on them. I will also cover basic BLE (Bluetooth Smart) reconnaissance.

This tutorial assumes you have a modern Linux system or VM running BlueZ. The commands below should work in BlueZ 4.101 and BlueZ 5.x.

Finding Bluetooth Devices

The most basic way to find local discoverable Bluetooth devices is to use hcitool scan. In the following example, there are two discoverable devices near my laptop: a Nexus 4 and a wireless speaker:

$ hcitool scan
Scanning ...
        98:D6:XX:XX:XX:XX      Nexus 4
        00:0D:XX:XX:XX:XX      Bluetooth Speaker

The left column is the device's BD ADDR (Bluetooth Device ADDRess). This address is unique to the device and is very similar to a WiFi or ethernet MAC address. The right column is the device's human-readable name, which the device sent us in response to our scan requests.

To get a little more information about a device, we can use hcitool inq, another subcommand of hcitool:

$ hcitool inq
Inquiring ...
        98:D6:XX:XX:XX:XX       clock offset: 0x0000    class: 0x5a020c
        00:0D:XX:XX:XX:XX       clock offset: 0x5a75    class: 0x240404

This output again includes the BD ADDR, but this time it also includes the clock offset and class of device. Clock offset is a low-level value that can be ignored. Class of Device (CoD) tells us what type of device we're talking to.

You can decode CoD using a tool I wrote called btclassify. Running it with the above classes tells us these devices identify as a phone and a wearable headset:

$ ./btclassify.py 0x5a020c 0x240404
0x5a020c: Phone (Smartphone): Telephony, Object Transfer, Capturing, Networking
0x240404: Audio/Video (Wearable Headset Device): Audio, Rendering

Diving Deeper: Services

Now that we know we have a phone and a headset (which is actually a speaker), we'd like to find out what services they run.

In Bluetooth service information is available via the Service Discovery Protocol, or SDP. BlueZ ships with sdptool for querying SDP. The browse subcommand is typically the best tool for listing services. It has fairly verbose output, so it's useful to filter it using grep:

$ sdptool browse 98:D6:XX:XX:XX:XX | grep Service\ Name
Service Name: Headset Gateway
Service Name: Handsfree Gateway
Service Name: AV Remote Control Target
Service Name: Advanced Audio
Service Name: Android Network Access Point
Service Name: Android Network User
Service Name: OBEX Phonebook Access Server
Service Name: OBEX Object Push

Given the presence of "Android Network" services, we can conclude that this device is likely an Android smart phone. The other services are relatively typical for a phone. For instance, Headset and Handsfree are used with headsets and car audio systems, and the OBEX services are used for transferring contacts and sharing files.

Unfortunately when we try to run sdptool browse against the speaker, we do not receive any records. Instead we can use the records subcommand to receive these records. This command runs for 20 seconds before terminating, so don't worry if it appears to have hung:

$ sdptool records 00:0D:XX:XX:XX:XX
Service RecHandle: 0x10001
Service Class ID List:
  "Audio Sink" (0x110b)
Protocol Descriptor List:
  "L2CAP" (0x0100)
    PSM: 25
  "AVDTP" (0x0019)
    uint16: 0x102
Profile Descriptor List:
  "Advanced Audio" (0x110d)
    Version: 0x0102

Service RecHandle: 0x10002
Service Class ID List:
  "AV Remote Target" (0x110c)
Protocol Descriptor List:
  "L2CAP" (0x0100)
    PSM: 23
  "AVCTP" (0x0017)
    uint16: 0x103
Profile Descriptor List:
  "AV Remote" (0x110e)
    Version: 0x0103

Service Name: Hands-Free unit
Service RecHandle: 0x10004
Service Class ID List:
  "Handsfree" (0x111e)
  "Generic Audio" (0x1203)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100
Profile Descriptor List:
  "Handsfree" (0x111e)
    Version: 0x0105

Pay attention to the values after "Service Class ID List". This tells us the device has "Audio Sink", "AV Remote Target", "Handsfree", and "Generic Audio" services. These services make sense given that we know this is a speaker.

Both of these commands give a complete breakdown of all lower-level protocols used to implement the services. This information is not typically useful during general reconnaissance, but it can be useful when developing fuzzers.

One final thing to note is that sdptool works even if a device is not discoverable. If you know a device's BD ADDR you can try to connect to it using sdptool browse or records to find out if it's nearby but undiscoverable.

Information Hidden by BlueZ

Certain devices return a bit more information that BlueZ does not display in hcitool output. You can get at this information using hcidump or BlueZ 5's btmon. Since hcidump works on all recent versions of BlueZ, I will demonstrate its use.

In one terminal run hcidump and tell it to log to a file:

$ sudo hcidump -w inquriy.cap

In another terminal run hcitool scan:

$ hcitool inq
Inquiring ...
        00:26:XX:XX:XX:XX       Richard Gill's MacBook Pro

Yowza, we can already see the name of the owner of a nearby laptop. Could be useful for social engineering. This naming convention is fairly common among Mac laptops. Worse, on at least some versions of Mac OS X when you put Bluetooth into discoverable mode it will remain in that mode indefinitely.

Kill hcidump and load the file it created in Wireshark. Filter the output to just inquiry responses using bthci.evt_code == 0x2f. If the device is friendly, you will see information similar to the following screenshot:

Under "Extended Inquiry Response Data" you can see a list of service UUIDs, which will be fairly similar to the output of sdptool. On the right I've highlighted a "manufacturer specific" field. This field helpfully tells us the specific model number of the laptop! This information is also highly useful for social engineering.

BLE Recon

All the of the above applies to classic Bluetooth devices, such as phones, headsets, speakers, and so forth. BLE devices are becoming increasingly common, and they require their own set of tools. Some examples of BLE devices are fitness wristbands, heart rate monitors, smart watches, proximity sensors, and so on.

Listing BLE Devices

The most basic tool to list local BLE devices is hcitool's subcommand lescan:

$ hcitool lescan
LE Scan ...
DC:A0:F2:B9:4F:9E (unknown)
DC:A0:F2:B9:4F:9E Flex
00:22:XX:00:XX:XX (unknown)
00:22:XX:00:XX:XX Polar H7 00XXXX

I haven't censored the first device because it is using a random address that can vary over time, a BLE security feature that makes tracking devices more difficult.

Given a bit of a-priori knowledge, we can assume the first device is a FitBit Flex. The second device is a Polar H7 heart rate monitor.

Listing BLE Services

Recent versions of BlueZ ship with gatttool for querying BLE services over GATT. The --primary command line switch connects to the device and asks it for a list of services:

$ gatttool --primary -b 00:22:XX:00:XX:XX          
attr handle = 0x0001, end grp handle = 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x000c, end grp handle = 0x000e uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle = 0x000f, end grp handle = 0x0014 uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle = 0x0015, end grp handle = 0x0023 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle = 0x0024, end grp handle = 0x0026 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle = 0x0027, end grp handle = 0xffff uuid: 6217ff49-ac7b-547e-eecf-016a06970ba9

The service UUID defines the service. UUIDs of the form 000018xx-0000-1000-8000-00805f9b34fb are generally 16-bit services that are assigned by the Bluetooth SIG. Information about these can be found on the GATT assigned numbers page.

Based on the UUIDs, we can see this device has "Generic Access", "Generic Attribute", "Heart Rate", "Device Information", and "Battery" services. The last UUID is a manufacturer-specific UUID. If you see another device with this service, it's likely a Polar H7.

Given the presence of the "Heart Rate" service we can assume this device is probably a heart rate monitor. The "Device Information Service" is more interesting, and I'll describe some fun tricks with that in the next section.

One thing to note: if you're trying to connect to a device using a random address, such as the FitBit Flex, you need to add the -t random command line flag. Let's list the services for that device:

$ gatttool -t random --primary -b DC:A0:F2:B9:4F:9E
attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x0008, end grp handle = 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle = 0x0009, end grp handle = 0x000e uuid: adabfb00-6e7d-4601-bda2-bffaa68956ba
attr handle = 0x000f, end grp handle = 0x0012 uuid: 558dfa00-4fa8-4105-9f02-4eaa93e62980
attr handle = 0x0013, end grp handle = 0x0018 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle = 0x0019, end grp handle = 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb

This device has many services in common with the heart rate monitor, but there are two additional manufacturer-specific services. Seeing these services on another device indicates you're probably looking at a FitBit Flex.

Finally, to see a list of all characteristics you can use the --characteristics flag or characteristics command in interactive mode. I will omit its output, since it's generally very long. Once you've found a characteristic you're interested in, you can try reading it using char-read-uuid or char-read-hnd.

Sensitive Information in Device Information Service

The "Device Information Service" is very interesting. From the SIG's page about it, we can see there is an optional field called "serial number". Clicking on the link brings us to the serial number string characteristic, which is assigned number 0x2a25. Let's use gatttool's interactive mode to try to read it:

$ gatttool -I -b 00:22:XX:00:XX:XX
[   ][00:22:XX:00:XX:XX][LE]> connect
[CON][00:22:XX:00:XX:XX][LE]> char-read-uuid 2a25
handle: 0x001b   value: 30 30 30 33 3X 3X 3X 3X 3X 3X 00 

This value is an ASCII representation of the serial number, which in this case is 0003XXXXXX. This value is likely unique and trackable.

Let's try that on the FitBit:

 $ gatttool -t random -I -b DC:A0:F2:B9:4F:9E
[   ][DC:A0:F2:B9:4F:9E][LE]> connect
[CON][DC:A0:F2:B9:4F:9E][LE]> char-read-uuid 2a25
[CON][DC:A0:F2:B9:4F:9E][LE]> Read characteristics by UUID failed: No attribute found within the given range

Too bad, it doesn't have it. One other interesting UUID to query is the manufacturer name:

[CON][DC:A0:F2:B9:4F:9E][LE]> char-read-uuid 2a29
handle: 0x0015   value: 46 69 74 62 69 74 00 00 00 00 00 00 00 00 00 00 00 00 00 

Converting this to ASCII gives us "FitBit", as expected.

One Last Thing

Using gatttool is nowhere near as reliable as the above makes it out to be. Connections will fail and drop all the time, even under controlled conditions. Just be patient and things generally work eventually.

Have fun doing Bluetooth recon!