InternalBlue: The perfect Bluetooth research device?

The perfect Bluetooth research tooling doesn't exist ;) But since I'm maintaining InternalBlue I can provide you with an overview of compatible devices and the advantages or shortcomings of all of these.

There is some open tooling for Bluetooth LE out there. Bluetooth LE is mostly used in IoT devices and modern gadgets. When it comes to Classic Bluetooth, which is still used a lot for audio devices and data transfer like tethering, you need to buy professional equipment or deal with very bad open-source implementations based on software-defined radios (SDRs). A brief overview of this can be found in my Bluetooth Hacking 101 talk from last year.

Despite not using anything based on SDRs or microcontrollers, I have a huge variety of devices. All of them have Broadcom (or "Cypress") Bluetooth chips. So, here is a minimal (seriously!) selection required to do some meaningful Bluetooth research that includes a couple of generations of devices and the possibility to test various stacks on top (if supported by iOS/macOS/Android/Linux).


Why build yet another wireless research tool?

InternalBlue was initially created by Dennis Mantz (@dennismantz), and co-supervised by Matthias Schulz (@dm5ms), who built NexMon for Broadcom Wi-Fi. InternalBlue and NexMon both use a different approach than other tools: They modify the firmware of a local device.

This means that they will always run on a full wireless stack. They support all proprietary features by the chip vendor and the upper layers, such as proprietary Apple protocols. They can also modify traffic on the modified device. However, further work is required to turn them into a sniffer or jammer, especially for Bluetooth. So, be aware that you're only able to modify the firmware of one device and usually don't run a classic machine-in-the-middle setup.


Broadcom has a main firmware running on the chip's ROM. They're using a separate ARM core for Wi-Fi and Bluetooth, and the cores are also different ARM variants. I think for Bluetooth it's always Cortex M3 and M4 (except from >8 year old devices, they might be ARM7). And Wi-Fi should be a Cortex R series. Thus, the concrete patching approach differs a lot between Bluetooth and Wi-Fi, and it also slightly differs between the Bluetooth variants. Either way, the chip's ROM is temporarily patched using the ARM Flashpatch unit with some branch instructions that jump into the RAM. A detailed explanation of that can be found in this previous blog post.

Firmware reverse-engineering

Firmware patching requires a lot of reverse-engineering. Thus, even if we could theoretically patch all firmwares of all devices, this is a lot of work. Yet, for a few Bluetooth devices, there are leaked symbols within Cypress WICED Studio 6.2-6.4. In 2016, Broadcom sold all their small customers and legacy chips to Cypress. They call this "IoT division" but actually it's more like legacy series. Since then, the implementations diverged, because Broadcom didn't supply Cypress with source code of firmware updates. This means two things:

  • Cypress chips have a very outdated base firmware (<2016).
  • BinDiff/Diaphora only detect very few symbols in an up-to-date iPhone/Samsung phone, since Broadcom did massive refactoring and code rewrites since then.
Anyway, there are a few devices for that we have symbols:
  • Cypress evaluation kits (CYW20735, CYW20819, CYW20819, CYW20706)
  • MacBook Pro 2016 (BCM20703A2)
So, if you're planning something like emulation with Frankenstein, go for one of these devices first. If you're looking for bugs... well, you'll find plenty of these, but you probably won't find anything that's exploitable on the newest Apple/Samsung device. Even though the evaluation kits have build dates going up to 2018, the firmware is more like 2015/2016. And the MacBook with the symbols, well, this is more like 2012, very similar to the Nexus 5 firmware :(

This means if you're planning to do some fancy exploitation or just want to play with the newest Bluetooth features, you'll have to do a lot of reverse-engineering.

While NexMon had the approach to just support a few chips with specific firmware versions very well, InternalBlue tries to SUPPORT ALL THE CHIPS. Thus, you can patch all of them, but you'll need to do a lot of the reverse-engineering on your own.

If you're into reverse-engineering and diffing, you'll enjoy these chips a lot. Broadcom has very bad version and library management. Each chip has its individual bugs. Their internal configuration toolbox might look something like this:

💥 Re-introduce old LMP library
      (Nexus 5 bug, fixed in Raspberry Pi 3+, but present again in MacBook Pro 2016 BCM20703A2)

🐛 EIR bug patch never backported and never sent to Cypress
      (Fixed in Galaxy S10e ROM, Broadcom claimed fix since Feb 2018 but present in CYW20819 ROM built in Apr 2018)

🐞 4-byte aligned Read_RAM will return zeros
      (Some registers need to be read 4-byte aligned and the Nexus 5 and BCM20703A2 handlers don't support this.)

💩 Launch_RAM either not thread-safe or doesn't work at all
      (Doesn't seem to work properly on most eval boards, threading issues on Nexus 6P, see my RNG measurement example scripts and patches.)

👾 Yet another memory allocator bugfix
     (Just to keep it exciting!)

💀 Fucked up memory allocator pool size
     (Misconfigured only on the CYW20735, but triggers all the time in Frankenstein.)

I probably forgot about a few flavors. These bugs appear, disappear, throughout all those firmware versions. So I'm like "oh noooo not this one again" etc. once I face them. I really hate everything. And depending on what you're planning to do, a certain chip just might not be for you.

Supported Bluetooth stacks

As of now, InternalBlue supports the following stacks: macOS, iOS, Android and Linux BlueZ. There are two variants of the iOS and Android implementations. And there might be some Linux BTstack support in the near future.

None of these implementations is "perfect" in that sense. The most stable and quite fast implementation is probably the original one with the Nexus 5 + Android 6.0.1. But then, you'll be stuck at a very old Bluetooth chip and stack.

Apple

iOS and macOS have a so-called PacketLogger, which is contained in the additional tools for Xcode. If you get the chip into diagnostic mode, it will even log LMP traffic etc. and correctly decode it. Depending on the PacketLogger version it will also do other fancy stuff such as printing the block buffer state, because Apple sometimes forgets to remove these features from the released versions. So, even though the Apple ecosystem is more closed than Linux, I really enjoy the PacketLogger support and how Apple integrates a lot of proprietary Broadcom chip features. Note that macOS and iOS have different Bluetooth stacks and also bluetoothd is a full rewrite. You might find different bugs in both of them :D


macOS

The macOS support was added by @unixb0y. InternalBlue hooks into IOBluetooth. Interestingly, despite being a private framework, this didn't change since macOS High Sierra. On older macOS versions it won't run/compile due to some Swift issues AFAIR.

Since it hooks into IOBluetooth, it supports any chip that works with macOS. I'm not aware of anything else than Broadcom, though. Moreover, since other vendors use other firmware patching approaches, it could only be used to overhear and inject HCI/ACL in that case and be rather boring.

I sometimes faced some performance issues on macOS. So, always double-check if your ROM dumps seem to be legit etc. But that might also be chip-related ;) Sometimes, it prints that a command timed out when it actually didn't.

With the BCM20703A2 chip, you even get symbols. So, even though its firmware is quite outdated, you can have a chip with symbols working on macOS Bug Sir, if you want that :D

The firmware files are stored in /S/L/F/IOBluetooth.framework/Resources. As of macOS Bug Sir, there are two issues:

  • Writing to Bluetooth RAM is no longer allowed after firmware initialization, no more live patching.
  • The firmware file can't be downgraded that easily because the system partition became write-only.

You can still create file system snapshots, which can be modified, and then boot these, as described here. Triple-check that the permissions are still the same, otherwise you might end up in a boot loop. And obviously, don't use your primary device for this, since you'll have to deactivate SIP and FileVault for this. It might be easier (and more secure?) to just stay on Catalina, I guess, where everything works with SIP etc. active. Anyway, you actually can run Catalina Bluetooth firmware on macOS Bug Sir :D


iOS

The iOS support with internalblued works since iOS 12, maybe even older versions, I just never tried it. The same internalblued also works on iOS 14. It hooks a bit deeper inside the stack and, thus, you can only run internalblued or bluetoothd. Yet, you can modify the firmware RAM and change between both daemons without losing your modifications. So, it's not that much of an issue for most of the debugging and patching. Also, the implementation is very fast, dumping ROMs or the RAM state is very smooth. A Frida-based dynamic implementation is still on my TODO list but whatever...

The initial support for UART Bluetooth was added by @ttdennis. Additional support for PCIe Bluetooth was added by @r0bre.

UART Bluetooth is used at least since the iPhone 6 series (never tested something older) up to the iPhone 8/X. Interestingly, also the iPhone XR has the same Bluetooth chip as the iPhone X, despite featuring a different CPU.

PCIe Bluetooth was introduced with the iPhone Xs and is still present in the iPhone 12. Since the iPhone 11 (and also on the iPhone 12), there are some debug strings included. This makes some of the firmware refactoring visible just by comparing the function names of these debug strings. Note that all other firmware versions that I saw before almost had no debug strings at all, so this is really great news! Oh, and @r0bre wrote a script to automatically rename the functions with debug strings in IDA (not public yet)... Oh, and the iPhone 12 uses 231 Patchram slots on iOS 14.4.

Android

The initial Android support hooks into the stack by modifying the Bluetooth module bluetooth.default.so. This is quite fast but also bad because the Bluetooth module needs to be re-compiled for each Android version and platform. However, it allows to add diagnostics support, and with this, also LMP sniffing.

As of now, the Nexus 5 + Android 6.0.1 combo is supported the best. I wouldn't recommend the Samsung Galaxy S6 / Nexus 6P, since this chip has a couple of issues. These include that if you use the default Launch_RAM HCI handler to execute code, this is somehow not thread-safe and will crash if there will be another HCI command/event within the next ~6 seconds. Since the first chip I wanted to add to InternalBlue after Dennis' thesis was the Nexus 6P, I thought this would be my fault and spent maybe 2-4 weeks on debugging this to find my bug... well :( I learnt my lesson and know that every Broadcom chip has different bugs including local interfaces.

Android 8 introduced an ABI to this module that enforces exclusive interfaces for HCI/ACL/SCO. Blindly enabling diagnostics will just crash the stack since it can't parse these packets. You can still send arbitrary commands, including the command to enable diagnostics, by echoing into the serial interface of the Bluetooth chip (usually mapped to /dev/ttySAC1).

Due to these changes in recent Android, I decided to build a very ugly hack that uses netcat on the same ports as the previous bluetooth.default.so extension. So it will work almost the same as the previous implementation but introduce a lot of delay. For whatever reason it's even slower on Android 11 than on Android 10, such that I had to increase timeouts. I know this is super hacky, but it's also super simple and works without installing any additional tools on a rooted Android phone.

So, if you're having issues with recompiling the Bluetooth stack, you can always enforce the serial netcat mode with the -s switch. But you'll lose the LMP/diagnostics capabilities and speed. You really don't want to dump a ROM like this.

I just dumped the ROMs with a local shell script that also echos into the serial interface and parsed the btsnoop_hci.log file later on :D No netcat in between, so the dump finishes within a reasonable time, but well...


Linux

As of now, there's only support for BlueZ. However, Maximilian Tschirschnitz, one of the authors of the Method Confusion attack on Bluetooth, also integrated BTstack in a local branch. So this might come to InternalBlue soon.

The Cypress evaluation boards can be attached to Linux, so these work quite great. Just don't be surprised if something goes wrong with BlueZ, because it doesn't support a lot of things and isn't that stable etc. Bluetooth on Linux, it's a thing... or not. I just hate it.

Even worse. The Raspberry Pi has Broadcom chips. But these have firmware compile dates of 2014. Also the "Bluetooth 5" compatible Raspberry Pi 4. It's just a RAM patch that changes the Bluetooth version since it's still compliant with Bluetooth 5. The specification's new version doesn't enforce any of the new PHY modes. So, while it's nice to have InternalBlue support on Raspberry Pis ... just don't use them. Don't use Bluetooth on these devices ever. The Patchram is on it's limit, so you won't have fun patching it on your own, and even worse, it likely misses security patches.

In theory, at least on Broadcom chips, there should be a vendor diagnostic interface to enable diagnostics and LMP, and btmon can even decode LMP. AFAIK there should even be a separate device in Wireshark that can be used for monitoring diagnostics then. In practice, I only had that working on a MacBook when I booted Ubuntu on it once.

But you can use Daniele Antonioli's patch that he developed for the KNOB attack. Instead of properly fixing BlueZ, he just allows the diagnostics command in the kernel and that's it. But you need to recompile the Linux kernel, then. Since I never had the need to get LMP monitoring to run on Linux, I didn't integrate that patch yet.

Anyway... considering that the Cypress evaluation boards ship with symbols it's a great platform for testing :) Just never ever use Linux+Cypress or Raspberry Pis in production. By the way, the Raspberry Pis now also belong to Cypress, despite formerly being owned by Broadcom, because they were part of that sold IoT division.


There are also real IoT devices with a Broadcom (now Cypress) chip, such as the Fitbit Ionic. If you have a bug, it's always worth a try to also test it on these devices. And the Fitbit security team has always been very kind to us :) So it's worth reporting your bugs. But they use a different stack, which I think is based on ThreadX similar to the evaluation kits in standalone mode, meaning that there's no InternalBlue support.



So... which device should I use?

As you see, it depends. Probably use the stack you want to research but start at a firmware with symbols for reverse-engineering. A lot of the features will be present in all devices :) Happy hacking!

Just don't consider any of the devices below, they don't have Broadcom Bluetooth chips.



Comments

Popular posts from this blog

Always-on Processor magic: How Find My works while iPhone is powered off

Embedding Frida in iOS TestFlight Apps

BlueZ: Linux Bluetooth Stack Overview