Sunday, March 16, 2014

Remotely Crashing Bluetooth on Android

At CanSecWest last week I demonstrated a remote Bluetooth stack crash in Bluedroid, Android's Bluetooth stack since Android 4.3. This post briefly describes the bug.

For the impatient, you can skip directly to the video of the crash.

The vulnerability is in Bluedroid's BLE (Bluetooth Smart) packet parsing code. In order to exercise this vulnerability, an attacker must force a user to connect to a malicious BLE device. Upon connection, the malicious device will issue a malformed GATT notification packet that causes the stack to crash.

It may sound a bit far-fetched that an attacker could force a user to connect to a device, but consider the fact that many BLE apps for Android opportunistically connect to any advertising device in order to determine if it is the device associated with that app. The app need only connect for this attack to succeed.

This vulnerability is not exploitable: the crash is caused by a FORTIFY_SOURCE check failure. Additionally, the vulnerability has been fixed since Android 4.4.

Show me the code

The code in question can be found in stack/gatt/gatt_cl.c, in gatt_process_notification (line 614). This is code for parsing notification packets, which are messages that a BLE device can periodically send to a BLE master. On line 626 you see the following code:

STREAM_TO_UINT16 (value.handle, p);
value.len = len - 2;
memcpy (value.value, p, value.len);

value.len is uint16_t. Both p and len are controlled by the attacker, though in this case we're only interested in len. p is the content of the packet sent by the attacker and len is the number of bytes in the packet.

The code expects a packet with a length of at least two bytes. If an attacker sends a malformed single byte packet, the calculation value.len = len - 2 will underflow to 65534. The memcpy will attempt to copy nearly 64k of data from p.

Demonstration

I've made a demonstration video of the remote Android Bluetooth stack crash.

I built an attack platform using a modified version of BlueZ, the Linux Bluetooth stack. BlueZ is configured to act as a BLE device running a GATT server. Whenever a BLE master connects to it, it automatically sends a malformed notification packet that is one byte long.

In the video, I demonstrate the vulnerability using a BLE heart rate monitor app. For the purpose of demonstration, I manually connect the app to the evil BlueZ. The stack crashes when the music stops playing.

The output of adb logcat contains lines similar to the following:


F/libc    (19174): FORTIFY_SOURCE: memcpy buffer overflow. Calling abort().
F/libc    (19174): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 19956 (BTU)

Again I note that this attack is not exploitable due to FORTIFY_SOURCE runtime checks. The code is instrumented at compile time where the length of the target buffer is known. At runtime, the code checks to see if the memcpy length is larger than the target buffer length and if so calls abort().

Timeline

This is the timeline following discovery of the bug:

  • 2013-09-30: Vulnerability disclosed to Google
  • 2013-10-07: Fix committed
  • 2013-10-30: Android 4.4 r0.9 tagged
  • 2013-10-31: Android 4.4 released with fix

Google did not issue a fix for this on Android 4.3, the rationale being that all users should upgrade to 4.4.

More Info

If you're interested in learning more about BLE active attacks and BLE fuzzing, check out the video of my CanSecWest talk, Outsmarting Bluetooth Smart.

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
[CON][00:22:XX:00:XX:XX][LE]> 
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!

Monday, January 27, 2014

BLE Fun With Ubertooth: Sniffing Bluetooth Smart and Cracking Its Crypto

Recently Omri Iluz wrote about his experiences capturing BLE very cheaply using an RTL-SDR and an MMDS downconverter. His work is very interesting and is a good way to get starting playing with BLE on the cheap.

A software defined radio approach is very powerful, and if you're interested in sniffing Bluetooth with SDR you should definitely check out gr-bluetooth. Another interesting approach is to use a narrowband radio as a sniffer, like the one on the Ubertooth.

I've been researching BLE (also known as Bluetooth Low Energy and Bluetooth Smart) since 2012, and I wanted to share the BLE sniffer I built on the Ubertooth platform. My sniffer is highly robust and can capture data from connections on data channels. I also discovered weaknesses in BLE's security and wrote a tool to decrypt packets under some circumstances.

The sniffer is turnkey and painless: if you have an Ubertooth you can begin sniffing packets right now by running a single command. Our tools capture to PCAP files that can be loaded into Wireshark for analysis using the BLE plugin that ships with recent development builds of Wireshark.

My BLE sniffer and Ubertooth itself are 100% open source. The source for the Ubertooth firmware, host tools, and board design can be found on the Ubertooth Github.

Technical Details

Ubertooth is an open source platform for Bluetooth research. It has a powerful ARM microcontroller connected to a reconfigurable radio chip, the TI CC2400. Although it was originally built to monitor classic Basic Rate (BR) Bluetooth, it serves as an excellent platform for building a BLE sniffer.

At the physical layer, our BLE sniffer works by configuring the CC2400's modulation parameters to match those of BLE. We also program the radio to search for a 32 bit value known as the Access Address that is at the beginning of every packet. When a nearby BLE device transmits, our radio sees the 32 bit Access Address and begins sending data to the ARM microcontroller.

Before we can read the data, we have to dewhiten it. This is done by XOR'ing the data with the output of a 7 bit LFSR. Our implementation dewhitens 32 bits at a time thanks to an impressive algorithm by Dominic Spill and Michael Ossmann. After this we parse the header and validate the CRC. Valid packets are passed up to the PC via USB where they are displayed and logged to PCAP files.

Timing Is Everything

Almost everything above happens on the Ubertooth dongle itself, and the PC just acts as a logging platform. This was a deliberate design choice made to satisfy one key requirement: timing.

In BLE, timing is everything. During connections devices hop to different channels relatively frequently, on the order of milliseconds. In this time we must receive the data, dewhiten it, parse the header, and make a decision about hopping very quickly. Sending the data to the PC and waiting for it to send a decision back would take too long for all but the slowest connections. USB latency alone is measured in milliseconds.

Additionally, on advertising channels and during connections two devices will transmit very quickly in sequence. First one device will transmit, and then 150 microseconds later the other will transmit. If we're busy analyzing the data from the first transmission, we may miss the second one altogether! This type of latency would be impossible to achieve over USB.

Following Connections

Following connections is where everything comes together. Advertising packets are sent on three channels in no particular order and can be captured easily. Connections hop along a sequence of 37 data channels very quickly, spending between 7.5 ms and 4 seconds on a given channel. If we wish to capture data from a BLE connection, we must hop along with the master and slave and listen for their packets on each data channel.

First we must sniff a CONNECT_REQ packet, which is transmitted by a BLE master device on an advertising channel. This packet initiates a connection between two devices and contains all the connection-specific details, such as Access Address, how frequently to hop, and in what order to visit data channels.

Once we have the details from the CONNECT_REQ packet, we have everything we need to follow along with the master and slave as they hop among the data channels. We hop to data channel 0 and wait for the first transmission. First the master transmits and then 150 microseconds later the slave transmits. We minimally process these packets and send them along to the PC. Then we hop to the next channel in the sequence and wait for the next packets. This continues until the master or slave closes the connection.

BLE conections are actually quite simple, significantly moreso than the hop pattern of BR Bluetooth. The only difficulty is meeting timing requirements, which we can do easily since all our processing occurs on the ARM microcontroller.

Promiscuous Capture

Our Ubertooth BLE sniffer also includes support for capturing data from connections that are already active at the time of sniffing. This feature, called promiscuous mode, is not supported by any other inexpensive commercial or open source sniffer. The only other tool I know of with support for this costs over US$ 20,000.

Due to the nature of BLE, without observing a CONNECT_REQ packet it is extremely difficult to recover all the parameters needed to successfully follow connections as they hop among the data channels. Hop timing, channel ordering, and even CRC calculation elude us.

I developed a few clever tricks to recover these key parameters using Ubertooth. Once we've recovered them, we feed them back into the normal connection following code and can actually begin following these active connections. For more details on how we recover the parameters, refer to my USENIX WOOT whitepaper.

Disclaimer: This mode is a little touchy: recovering the parameters can be tricky and we don't filter false positives well. However, once the parameters have been recovered, connection following is just as robust as if the CONNECT_REQ packet had been observed.

Cracking Encryption

In early 2013 I discovered that BLE's encryption has a fatal flaw. I wrote a tool called crackle to automatically exploit this flaw and decrypt encrypted BLE data.

An attacker present during pairing can recover the encryption keys used to protect data during connections. Furthermore, since these encryption keys are reused, this attacker can decrypt every future conversation between the master and slave devices.

This attack is completely passive. The attacker simply has to capture the packets sent by the pairing devices using a tool such as Ubertooth. No packets are ever transmitted by the attacker, and the victims will have no knowledge that they are being eavesdropped on.

If you give crackle a PCAP file that contains the pairing data, it will automatically crack the encryption key and decrypt any further data sent during the connection. If you give it a key and a PCAP file filled with encrypted data, it will decrypt the data.

Obviously this is a huge weakness in BLE and severely weakens the security of the system. I was surprised that, although this weakness has been public for a while, the latest version of the Bluetooth Core Specification (version 4.1, published in December 2013) does not address it.

More Info

I've intentionally left out a lot of details since this blog post is already long-winded enough as-is. If you're interested in more depth, you can do any of the following:


Ubertooth can be purchased from several places, the full list is available on the Great Scott Gadgets web site, though I always get mine from Hacker Warehouse.

Finally I would like to express thanks to the many people who helped make this work possible, but in particular:

  • Michael Ossmann (@michaelossmann) for creating the Ubertooth
  • Dominic Spill (@dominicgs), the current Ubertooth maintainer
  • Michal Labedzki, for getting my BLE Wireshark plugin into Wireshark