Note: I am a lazy fuck and I have been putting off this post for a while so I just dumped some stuff in my text editor and put it up. I plan to refine this periodically over time. I will leave notes here while I update it. If this stuff is useful to you and you are running into problems setting stuff up or whatever, PM me on twitter.
I started digging into bluetooth stacks after Armis announced its series of vulnerabilities affecting Linux, Android, iOS, and Windows, which they named Bluebourne. This paper explaining the vulnerabilities as well as the follow up explaining the exploitation were very well written and I highly recommend you take a look at them. If you want to run their POC, you can check it out here, and if you want to adopt this POC to your device, take a look at this.
Trying to make sense of these disclosed vulnerabilities, along with their POCs, I tried to find some online resources to help me out. There were a lot of interesting projects dealing with the application layer of bluetooth and how applications which use this technology expose themselves to potential issues. But, there was very little in the way of analyzing the actual bluetooth stack which enables these higher level applications.
TODO: resources that I found.
I initially wanted to be able to speak the protocol in hopes I could write a fuzzer or something to shake some bugs out of bluetooth stack code. Bluekitchen’s bluetooth documentation and implementation helped immensely as I had a means of sending data to a target device.
I searched for vulnerabilities in Android for a while with no luck. But over the period of time in this research I learned a great deal about Bluetooth and watched as seasoned bug finding veterans crushed this source code.
The initial post I want to make will just outline different components of Bluetooth and how they relate to each other. Additionally, I want to point out the attack surface of these components and vulnerabilities in these components within their implementation (mostly Android).
I will be following this post up with some helpful instructions for running and debugging Bluetooth POCs to help with your own bug hunting.
Bluetooth enabled things
A bunch of things use bluetooth, here are some stack implementations I am aware of:
MacOS Stack - written in objc
iOS Stack - written in c
Android (fluoride)
BTStack
mynewt
nimble - zephyr
Windows
Toshiba
Linux (bluez)
Car entertainment systems
HCI
Notable features
Interfaces with the bluetooth controller - For example, whenever a packet is sent, the controller will tell the stack how many packets were sent via HCI (TODO image)
A common naming convention for packet buffers is pdu (protocol data unit)
For l2cap, HCI creates handles which it passes up after a successful connection
Link Manager Protocol (LMP) is also worth mentioning here as it “The Link Manager carries out link setup, authentication, link configuration and other protocols. It discovers other remote LM’s and communicates with them via the Link Manager Protocol (LMP).” (info)
Not a whole lot going on since this layer is just in charge of talking to a controller and passing data along to higher levels
ECC attack for MiTM (TODO: Link)
What is interesting about the attack surface is that for each protocol, Android has a server and a client. For example, the Android phone can receive and parse SDP packets, as well as send them to a device it is in the process of connecting to. While we would typically need to find some triggering condition to have the client issue requests from us and parse their response, this is an interesting attack surface as it might be less likely developers will think about the security of parsing the response from the server. As we will see in the various protocol client applications, this was indeed the case.
Stack Implementations
Scapy
Scapy gives a nice overview of how packets are structured, but because of the weirdness of the bluetooth protocol, this information only gets you so far.
If you want to dig into the details of Bluetooth, I recommend looking through Bluekitchen’s btstack. Here is BTStack’s main hci event handler.
HCI is not entirely interesting, it is mainly used for configuring the Bluetooth controller, creating/configuring connections and sending/receiving data to devices (power on, off, start advertising le data, create connection). (TODO: Link to btstack hci_cmd.c)
Packet retransmission/reassembly - potentially sketchy code (TODO link to different implementations)
Both client and server send each other their mtus (max transmission unit) to specify how much data they can send (one of the vulnerabilities in the BlueBourne research used this to trigger a vuln TODO: link)
Static vs. Dynamic channels
There are some pre-defined ranges by the bluetooth standard
The channels are different for br/edr and le connections
A protocol is identified by a psm (e.g. SDP has psm 1, ATT has psm 7, a really good list can be found in bluez’s sdptool sdptool.c:259, when we get to SDP we will look at this more)
After connecting to a protocol, the are given a cid (channel id) which lets you send acl (data) packets to
Signalling Channel
The entrypoint for creating and configuring channels with a remote device (btstack l2cap_signalling.c:53)
classic (br/edr) and low-energy (le) exist in l2cap, their code paths somewhat merge
This can be seen in btstack/src/l2cap.c:3443
Attack Surface
Channels and their state are created and stored within the stack, abusing the state machine could lead to use-after-frees
TODO: Go through each bluetooth stack and show what channels are registered (point out the weird iOS stuff)
Stack Comparisions
CVEs
CVE-2017-0781 RCE (Allocate buffers of the right size when BT_HDR is included) diff
Vuln used by Bluebourne in their exploit POC, the code when run would cause a heap overflow due to the allocation being too small
CVE-2018-9359 Fix OOB read in process_l2cap_cmd (signalling commands ID) diff
Pretty much no signalling commands were checking minimum length and variables read from the packet were sent back to the user
This is probably the most sketch protocol in Bluetooth. There is a lot going on with the protocol and it is required to be exposed to all devices so they know what applications the device has registered (e.g. can I send music to you? yes! I have AV controller!). Granted, devices that operate only with BLE do not have this since information is advertised via GATT. However, all mobile devices, cars, and things that need compatability with older protocols will be listening for SDP
Notable Features
The SDP server handles remote queries of the SDP database which contains information for all registered services for the device. For example…
Each Bluetooth protocol is assigned a specific number defined by the specification
Higher level applications register themselves to the server via the internal SDP API the server exposes (as seen here in btstack for PAN: ). These applications identify themselves to remote devices using service class identifiers (Bluez)
Each of these higher level protocols use different data elements (below) to convey to a remote device how the application is configured (metadata about the bluetooth application), these are identified by service attribute definitions (seen here in Bluez). For example, here is the SDP registration specification for PAN. We can see btstack specifically parsing an RFCOMM SDP entry: examples/sdp_rfcomm_query.c
The SDP client performs queries and parses their response
There are three different queries which can be performed: (TODO fill in these details)
ServiceSearchRequest
ServiceAttributeRequest
ServiceSearchAttributeRequest
Queries are comprised of data elements which are type, length, value structures (seen here: btstack sdp_util.h:105)
These data elements
The parsing is relatively complex, I think bluez’s implementation is the clearest
If a response is too big, a continuation state is created (TODO: Reference specification)
This continuation state has led to a number of vulnerabilities with Android (TODO: refs) due to the server either trusting the client’s state or the internal state becomes corrupt and lengths become out of sync (TODO: ref bluebourne exploit leak)
Attack Surface
Since every device must always expose their SDP server (allow JustWorks pairing, see HCI/L2cap) to all nearby devices to tell them what sevices are accessible on the device, this provides a nice no-interaction attack surface. Additionally, a given bluetooth stack might have some sort of automated trigger (see iOS Airpod discovery) which causes it to use its SDP client to send a request and parse a response from the attacker’s device. Again, a no-interaction needed attack surface.
The SDP protocol is sufficiently complex to most likely contain bugs in any implementation, as shown in researchers digging through Android.
TODO: Run sdp tool on each stack
This code just dumps out relavant info for understanding the BR/EDR attack surface of a device. For a more comprehensive view of what data SDP holds, check out this full SDP dump for the same device:
Hard to exploit: You can cause memcpy to copy a huge amount of bytes onto the heap, but where you need to control data to write the heap cookie you aren’t able to control it.
This one is actually pretty interesting. num_uuid was previously set to 2 which when copying from uuid_list (located on the stack as Uuid uuid_list[1];) would copy an additional sizeof(Uuid) bytes into the uuid_filters array for the SDP entry. This data would then be sent if device received a service search attribute response (sdp_discovery.cc:584) and a continuation request is needed (sdp_discovery.cc:563).
CVE-2017-13290 SDP ID [diff]https://android.googlesource.com/platform/system/bt/+/72b1cebaa9cc7ace841d887f0d4a4bf6daccde6e)
The end of the request was never checked. This is the same problem as seen in other areas of the stack, but the approach to fixing is a lot more consistent than other fixes.
The end of the request is checked accross many different functions with this patch.
Similar to CVE-2017-13290 but this fixes reading from the end of the request in the client.
BNEP and PAN
Notable Features
BNEP (btstack: btstack/src/classic/bnep.c)
Protocol that PAN operates on. In case some other service wanted to implement some network-esc thing? I have only ever seen PAN use this protocol…
The protocol is not terribly interesting, most implementations ignore certain parts of the specification because they are literally never used lol (TODO link to linux extension bit).
PAN
Different roles PANU, NU, GN
Attack Surface
TODO
CVEs
CVE-2017-0782 (Add a missing check for PAN buffer size before copying data) diff and (Add missing extension length check while parsing BNEP control packets
) diff
this code will always overflow (see bluebourne paper)
CVE-2017-0783 (Disable PAN Reverse Tethering when connection originated by the Remote) diff
Length check is missing, you can position p so that it points to the byte after the packet and if it is > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG then it will be sent back
It is basically a glorified database which uses UUIDs to identify elements to read and/or write
Service, characteristics, attributes
Attack surface
The code for each off the different actions is relatively limited in what it does (hence the “low energy”). So for as far as exploiting the GATT protocol, there is little room for vulnerabilities to be introduced.
There is a lot of research published on exploiting applications which use GATT (bleah) by identifying information that is exposed and properties that are able to be written to.
A really cool challenge that you can try out to learn about BLE application layer hacking is here: https://github.com/hackgnar/ble_ctf
Security is hard, especially when you are implementing code to match a specification that has a number of protocols some legacy, some new.
When you are parsing data, for the love of god, properly keep track of where you are. Linux and iOS do this well by having the position in the packet always being kept updated and checked. Android fails to do this and is the root cause of the majority of the CVEs that have been reported.
Attack surface
Following the guidelines put forth by NIST, a Bluetooth stack can take some steps to become secure to the passer by attacker. While a Bluetooth social engineering attack (prompting the user to pair a device) can open up the attack surface to other protocols, it does put at least some barrier to protect devices from rampantly spreading malware.
Vulnerability Patterns
It is important to identify vulnerability trends and cut the head off the Hydra before you have new ones. As seen in reported Bluetooth vulnerabilities in Android, the head was not cut off. You have patches which fix a vulnerability, but create a new one (BNEP UAF), lack of length checks (all the information disclosures), and overall neglect of properly checking lengths in general (AVCTP length check, the bnep off by one).
Google’s blog post about security improvements in Android Q was very exciting since they are using data drive their security efforts in creating analyses which stop bug pattens like these.