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.

1 comment:

  1. Hello Mike,

    is it sure that the bluez is configured as GATT server? Because I was able to control the LED of my BLE slave device using the Gatttool in linux. And as far as I know it is normally not possible to get two BLE slave devie connected. If the bluez is the server how was I able to connect to another slave then?

    Is it possible to get the source code of the bluez you used to fuzz?

    Thank you

    ReplyDelete