This blog post presents our fuzzer for the Bluetooth Low Energy GATT layer and the related vulnerabilities found with it.
Introduction
Bluetooth Low Energy (BLE) is a widely adopted wireless communication technology used by billions of devices in various applications. These
applications range from IoT domain to more sensitive devices such as medical ones.
BLE has been subject to a lot of research so far [1, 2, 3], but only a few of them targeted specification corner cases which require high-level
manipulation of the GATT layer.
Based on that reason, we decided to build a fuzzer based on attack scenarios defined after conducting an in-depth study of the BLE specification. Our work resulted in the discovery of non-conformities, bugs, and vulnerabilities in various BLE stacks.
This R&D work was carried out during Baptiste Boyer's internship at Quarkslab.
BLE analysis
The BLE protocol is built upon multiple layers that extend from the radio layer to the application layer as described below:
BLE Stack
Our study focuses on the Attribute Protocol (ATT) layer and on the Generic Attribute Protocol (GATT) layer. However, it is also important to define the two key components of the BLE framework that are the Host and the Controller.
The Host and Controller represent distinct entities with specific roles in the communication process. The Host is typically associated with the device’s primary processing unit, such as a computer or smartphone. It oversees higher layers of the BLE protocol stack, managing connections, configuring parameters, and handling application-specific communication needs. In contrast, the Controller operates at a lower layer, responsible for radio frequency communication aspects. Implemented in specialized hardware, like a Bluetooth chip, the Controller executes tasks such as frequency hopping, modulation, and power control, ensuring reliable and efficient radio communication. To be able to communicate together, they use the Host Controller Interface (HCI).
ATT Layer
The Attribute Protocol (ATT) defines two distinct roles: a server and a client. The server is responsible for storing and managing attributes, while the client accesses and manipulates these attributes. In this context, an attribute is a data representation format composed of four fields.
The Attribute data structure has the following format:
Attribute field | Size (bytes) | Description |
---|---|---|
Handle | 2 | A unique identifier assigned to each attribute, allowing devices to reference and interact with them. |
UUID | 2 or 16 | An identifier that uniquely identifies a specific attribute type, defining its purpose and characteristics. |
Value | Variable length | The actual data associated with an attribute, representing the information communicated between devices. |
Permissions | Implementation specific | Access rights and restrictions governing how and attribute can be read, written, or otherwise interacted with by devices, ensuring security and control over the data exchange. |
The ATT Protocol outlines methods for both reading and writing attributes. These methods involve ATT Protocol Data Unit (PDU) for communication. In the context of the ATT protocol, a PDU represents the packet that is exchanged with the lower layer – specifically, the L2CAP layer. This packet is then encapsulated for transmission over the physical link or sent to the upper layers.
Attribute PDUs have the following format:
Name | Size (bytes) | Description |
---|---|---|
Attribute Opcode | 1 | The attribute PDU operation code. bit 7: Authentication Signature Flag. bit 6: Command Flag. bits 5-0: Method. |
Attribute Parameters | 0 to (ATT_MTU - X) | The attribute PDU parameters. X = 1 if Authentication Signature Flag of the Attribute code is 0. X = 13 if Authentication Signature Flag of the Attribute code is 1. |
Authentication Signature | 0 or 12 | Optional authentication signature for the Attribute Opcode and Attribute Parameters. |
Let’s elaborate on the behavior of the ATT PDU called Prepare Write Request
, as most of our findings are associated with this ATT PDU.
The Prepare Write Request
ATT PDU is vital when dealing with the need to
write a long Attribute value, i.e., an attribute value where its size
exceeds (ATT_MTU - 1). The default Maximum Transmission Unit (MTU) in
BLE communications is 23 bytes. This ATT PDU is used to request the server to
prepare the write of a value for a specified attribute. The server responds with a
Prepare Write Response
to confirm the correct reception of the value. Multiple
Prepare Write Request
ATT PDUs may be sent to transmit the complete Attribute
value. Once all the ATT PDUs have been transmitted, the client sends an Execute Write Request
to instruct the server to write the value.
The format of the Prepare Write Request
is as follows:
Parameter | Size (bytes) | Description |
---|---|---|
Attribute Opcode | 1 | 0x16 = ATT_PREPARE_WRITE_REQ PDU. |
Attribute Handle | 2 | The handle of the attribute to be written. |
Attribute Offset | 2 | The offset of the first byte to be written. |
Part Attribute Value | 0 to (ATT_MTU-5) | The value of the attribute to be written. |
GATT Layer
The Generic Attribute Profile (GATT) establishes a service framework built upon the ATT Protocol. This framework defines procedures and formats for services and their characteristics are defined. These procedures encompass various operations such as discovering, reading, writing characteristics but also notifying and indicating any characteristic value modification. Additionally, GATT outlines procedures for configuring the broadcast of characteristics. It also defines some standard profiles with associated services and characteristics.
The GATT Profile establishes the format for exchanging profile data, defining fundamental elements such as services and characteristics within the structure. These elements are encapsulated by Attributes, which serve as containers for carrying profile data in the ATT Protocol.
GATT Profile Hierarchy
Attack scenarios
After an in-depth study of the specification, 9 attack scenarios were defined. The main goal of this study was to pinpoint corner cases and inaccuracies within the specification, providing a foundation for the development of precise attack scenarios.
The description of the scenarios is provided in the related paper.
Fuzzer
The attack scenarios were implemented as fuzzing scripts in Python using the WHAD framework.
We opted for WHAD as our chosen framework for its specific capabilities in the BLE context. This framework equips us with all the essential tools for testing the GATT layer, including transparent PDUs logging and its own BLE stack implementation. It offers simple methods to create and send BLE packets, encompassing the entire spectrum of ATT possibilities. Additionally, it facilitates the seamless setup of a GATT server and enables straightforward modification of its behavior.
The fuzzer architecture was designed with certain key choices in mind. One notable decision involved the type of connection established during a fuzzing session. Instead of initiating a new connection for each test case, we opted for a single connection for the entire fuzzing session. This choice was driven by the belief that retaining previous states of the stack could potentially aid in triggering and identifying bugs.
We opted for a randomized approach to populate the ATT PDUs. An example illustrating the Prepare Write Request
ATT PDU
mentioned earlier is provided below. Additionally, it is worth noting that each
fuzzing session focused solely on testing a single scenario.
def mutate_fill_payload(att_proc, gatt_handle):
"""
Fills and returns the ATT primitive
"""
match att_proc:
...
case scapy.layers.bluetooth.ATT_Prepare_Write_Request:
_gatt_handle = random.choice(gatt_handle)
_offset = random.randint(0,65535)
n = random.randint(0,80)
_data = random.randbytes(n)
return ATT_Prepare_Write_Request(gatt_handle = _gatt_handle,
offset = _offset,
data = _data) , 5 + n
Several parameters are set through the CLI interface, the help option displays the following content:
CLI help output
The tool implementing the scripts scenario can be found on Quarkslab's GitHub.
Results
Only the vulnerabilities are discussed in this section. The description of the non-conformities and bugs is provided in the related paper.
Espressif GATT server example
This vulnerability is associated with the Bluedroid stack provided in the ESP-IDF framework. More specifically, it is related to the GATT server example provided for Espressif devices, intended for using Bluedroid. This vulnerability exposes a risk of heap overflow.
We uncovered this vulnerability during the code review of the Bluedroid stack. Building on our prior discoveries of bugs, our aim was to assess the impact on user applications. Upon scrutinizing the provided GATT server example, we finally identified this Out-of-Bounds write issue.
Their initial misguided decision involves allowing the user to verify the
conformity of parameters provided in the Prepare Write Request
ATT PDU by
default.
The root cause of the vulnerability was located in the example_writ_event_env()
function during the copy of a received Prepare Write Request
’s value
into the allocated buffer prepare_buf
as we can see in the code below:
memcpy(prepare_write_env->prepare_buf + param->write.offset,
param->write.value,
param->write.len);
An attacker controls both the offset and the value and is able to write outside
of the allocated buffer. A check on the offset is actually done but only when the allocated
buffer has already been allocated, and therefore this check is not performed for
the first received Prepare Write Request
.
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
[...]
if (prepare_write_env->prepare_buf == NULL) {
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE*sizeof(uint8_t));
prepare_write_env->prepare_len = 0;
if (prepare_write_env->prepare_buf == NULL) {
ESP_LOGE(GATTS_TAG, "Gatt_server prep no mem\n");
status = ESP_GATT_NO_RESOURCES;
}
} else {
if(param->write.offset > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_OFFSET;
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_ATTR_LEN;
}
}
Unfortunately, Espressif did not categorize this as a vulnerability within their bounty program, treating it solely as a bug despite its clear manifestation as a heap overflow issue. However, following our report, this vulnerability has been fixed in a timely manner by Espressif without any communication about it, affecting 7 of their code examples. We are curious to know about the number of applications that relied on these code examples and remain susceptible to our discovery.
Espressif's response: "Regarding the issue with the example memcopy, this problematic code segment is not present in the host and controller codes. It is solely included in the Example to demonstrate how the ESP API is used. Typically, customer code is autonomously developed based on the API, and the impact of this issue on customers is minor, lacking any substantial consequences."
CVE-2024-24746
Denial of Service of NimBLE Bluetooth stack.
During the analysis of the log files from our fuzzing campaign,
we observed instances where the device has terminated the connection by itself.
Upon further investigation, we identified a recurring pattern associated with
disconnections: transactions involving Prepare Write Requests
that were not
completed within a 30-second timeframe.
Indeed, the BLE specification stipulates that "A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed, and the local higher layers shall be informed of this failure." [Spec Vol.3 Part.F 3.3.3].
NimBLE implements this feature with the BLE_ATT_SVR_QUEUE_WRITE_TMO
timer.
When the initiating device sends a Prepare Write Request
to the BLE
peripheral, the NimBLE stack starts a timer to remove later the pending write
operations if no Execute Write Request
or Prepare Write Request
is received
within the specified time frame. If the initiating device disconnects from the
peripheral just before the timeout is reached, then the peripheral will be stuck
in an infinite loop and therefore will not advertise anymore even if the current
connection has been terminated. This lack of advertising prevents any new connections,
resulting in the device remaining unconnectable until it is reset.
The following schema shows an overview of what is happening:
NimBLE Denial of Service
Sony headsets
Denial of Service of Sony headsets.
We wanted to reproduce CVE-2024-24746 on real-world devices. We opted for commonly available audio devices, including the Sony WH-1000XM4, WF-1000XM4 and WH-1000XM5, as some colleagues had these models on hand. We successfully managed to crash all these devices by attacking their exposed BLE GATT servers in the same manner as we did with the NimBLE GATT server.
In the following, we will detail the Denial of Service attack process only for the Sony WH-1000XM4. Similar processes have been used for the WF-1000XM4 and WH-1000XM5.
By default when used with Bluetooth Classic to listen to music, this device
like many Bluetooth audio devices exposes a BLE GATT server typically
labeled as LE_WH-1000XM4, featuring a range of characteristics with various
permissions. Our goal was to find an enabled Prepare Write Request
characteristic.
We discovered the service with the 16-bit UUID FE2C, known as the Fast Pair Service, which is present
on many Bluetooth audio devices. This service has characteristics with write
permissions.
We noticed that following a Prepare Write Request
with
an Execute Write Request
caused the headset to disconnect by itself.
At this point, it became evident that we encountered a scenario similar to
the NimBLE DoS vulnerability.
After sending a single random request before each connection drop, we identified an
ATT PDU that consistently caused the device to crash after few try, a Find By Type Value Request
with specific parameters.
The following schema shows an overview of what is happening:
Sony WH-1000XM4 Denial of Service
A Proof of Concept for this vulnerability is provided on Quarkslab's GitHub.
Conclusion
In this blog post, we conducted an in-depth analysis of the BLE specification, leading us to elaborate and implement attack scenarios using the WHAD framework. Our research uncovered several non-conformities, bugs, and vulnerabilities across multiple BLE stacks, highlighting the need for more attention and improvement in these layers to enhance overall security.
More detail can be found in the related paper.
Disclosure timeline
Espressif
- 2023-12-05 Quarkslab sent report via email.
- 2023-12-06 Espressif acknowledged the report and asked details to be resent in plaintext.
- 2023-12-06 Quarkslab sent the report in plaintext.
- 2023-12-07 Espressif confirmed they received the report.
- 2023-12-21 Espressif said it could reproduce the two bugs (DoS, OOB write) but they do not consider them vulnerabilities.
- 2023-12-23 Quarkslab acknowledged the last email and asked if Espressif could elaborate on the criteria used to triage the bugs.
- 2023-12-29 Espressif replied that impact of the first bug is just disconnection of the attached device, since it does not impact normal use nor leak user data it cannot be considered a vulnerability. The second bug (OOB write) is not present in Host or Controller code, it only affects example code and customers typically develop autonomously based on the API, so the impact is minimal.
- 2024-01-19 Quarkslab sent report via email to Security Team.
- 2024-01-21 Apache MyNewt PMC acknowledged the report.
- 2024-01-25 Apache developer confirmed the report and said they are working on a fix.
- 2024-02-06 Quarkslab acknowledged the last email.
- 2024-02-07 Apache MyNewt PMC said it had sent a proposed patch for testing a week ago
- 2024-02-13 Apache asked if Quarkslab could test the patch.
- 2024-02-14 Quarsklab replied that they tested the patch and could not reproduce the bug.
- 2024-02-14 Apache MyNewt PMC published a fix.
- 2024-04-05 Apache MyNewt PMC assigned CVE ID CVE-2024-24746 to the vulnerability.
- 2024-04-05 Quarkslab asked Apache to acknowledge Baptiste Boyer as reporter.
- 2024-10-25 Blog post is published.
Sony headsets
- 2024-07-22 Quarkslab sent report via email to Sony.
- 2024-07-23 Sony acknowledged the report.
- 2024-07-31 Sony asked for more details to be able to reproduce the Denial of Service.
- 2024-08-05 Quarkslab sent more details and Proof of Concept program.
- 2024-08-06 Sony said it had reproduced the bug in one model but now on the other two and asked to Quarkslab to try with auto power off turned off
- 2024-08-06 Quarkslab re-sent the PoC program, since Sony received it mangled in the prior email.
- 2024-08-12 Quarkslab confirmed the bug persists with auto power off disabled and sent a WHAD-based fuzzer to Sony.
- 2024-08-19 Sony they were working on identifying the root cause of the bug, asked where the research would be presented.
- 2024-09-09 Sony said it is working on fixes and asked how to acknowledge the report. Also asked where will the research be presented.
- 2024-09-10 Quarkslab replied asked to acknowledge Baptiste Boyer, and said he would present at the hardwear.io conference.
- 2024-09-12 Sony asked the day of the presentation to coordinate publication on their web site, also requested the slides.
- 2024-09-13 Quarkslab replied that it will provide the slides as a courtesy when they are ready.
- 2024-10-02 Sony published a fix for WH-1000XM5.
- 2024-10-17 Sony published fixes for WH-1000XM4 and WF-1000XM4.
- 2024-10-21 Quarkslab sent the slides of the hardwear.io talk to Sony.
- 2024-10-25 Sony acknowledged Quarkslab for the vulnerabilities finding.
- 2024-10-25 Blog post is published.