Home

Awesome

BrakTooth Proof of Concept Attacks (+ BT Fuzzing Framework)

<p align="center"> <img src="./docs/braktooth_logo.png" alt="mode_master" width="650" height="auto" /> </p> <p align="center"> <img src="./docs/poc_setup.png" alt="mode_master" width="1000" height="auto" /> </p>

[!TIP]



1) Requirements

BrakTooth requires a specific BT hardware development kit (ESP-WROVER-KIT) to be able to launch the attack since LMP packets cannot be sent from the host in normal Bluetooth Hardware.

​ We recommend running native Ubuntu 18.04 / 22.04 since we rely in USB low-latency for correct Baseband interception with ESP32 LMP stack.

<p align="left"> <img src="./docs/esp32.jpg" width="200" height="auto" /> </p> The recommended hardware is [ESP-WROVER-KIT-VE](https://www.espressif.com/en/products/hardware/esp-wrover-kit/overview). You can buy this board from several electronics suppliers and online stores such as:

2) Installation Instructions (x86 / ARM64)

2.1) Install (flash) PoC firmware on ESP-WROVER-KIT

First, connect ESP32-WROVER-KIT to your PC. You can check if two serial ports were added by running ls /dev/ttyUSB*. Normally, ESP32-WROVER-KIT adds two serial ports such as /dev/ttyUSB0 and /dev/ttyUSB1. We want the second serial port, which is used for serial communication with ESP32.

wget https://github.com/Matheus-Garbelini/braktooth_esp32_bluetooth_classic_attacks/releases/download/v1.2.0/esp32driver.zip
sudo apt install -y unzip python3-dev python3-venv
unzip esp32driver.zip # Extract esp32driver.zip (firmware package)
cd release
python3 firmware.py flash /dev/ttyUSB1 # Please change your serial port to match your ESP32 device.
# You may need to press and hold the "Boot" button during the flashing process.
cd ../

[!IMPORTANT]
Source Code of the firmware is available in this repo: https://github.com/Matheus-Garbelini/esp32_firmware_patching_framework

2.2) Install Braktooth

# Install zstandard, wget and unzip
sudo apt install -y zstd wget unzip
# Download binary release for x86 or arm64
wget https://github.com/Matheus-Garbelini/braktooth_esp32_bluetooth_classic_attacks/releases/download/v1.2.0/wdissector_$(uname -m).tar.zst
# Extract the full wdissector compressed release file from releases page
tar -I zstd wdissector_$(uname -m).tar.zst
cd wdissector
# Install package requirements for Ubuntu 18.04
# It installs python3, nodejs, and system packages using apt-get
./requirements.sh

3) Running BT fuzzer (GUI or Terminal)

You can start the fuzzer as follows:

sudo bin/bt_fuzzer --scan # Scan for targets (BDAddress) for 15 seconds
sudo bin/bt_fuzzer --gui --autostart --target=E8:D0:3C:94:2C:66 # Start fuzzer with graphical user interface (GUI)
sudo bin/bt_fuzzer --autostart --target=E8:D0:3C:94:2C:66  # Start fuzzer without GUI  

BT Command line options

sudo bin/bt_fuzzer --help
Bluetooth Classic Fuzzer (Baseband, LMP, L2CAP, etc)
Usage:
  BT Fuzzer [OPTION...]

      --help               Print help
      --default-config     Start with default config
      --autostart          Automatically start (default: true)
      --no-gui             Start without GUI
      --test-webview       Test GUI webview performance (requires internet)
      --live-capture       Open wireshark in live capture mode
      --exploit [=arg(=)]  Exploit Name
      --list-exploits      List all exploits
      --host arg           Host BDAddress
      --host-port arg      Host serial port name of BT Interface 
                           (ESP-WROVER-KIT)
      --random_bdaddress   Enable/Disable host BDAddress randomization
      --target arg         Target BDAddress (default: /dev/ttyUSB1)
      --target-port arg    Target serial port name to detect crashes 
                           (default: /dev/ttyUSB2)
      --target-baud arg    Target baud rate (default: 115200)
      --bounding           Enable/Disable Bounding (default: true)
      --iocap arg          IO Capabilities (default: 3)
      --authreq arg        Authentication Request flag (default: 3)
      --scan               Scan BT Targets

3.1) Running Experimental Fuzzers:

Wi-Fi AP Fuzzer (WIP)

Wi-Fi AP Fuzzer requires use of Alpha AWUS036AC Wi-Fi Dongle and installation of our custom driver for it: cd src/drivers/wifi/rtl8812au && make -j4. Then, the Wi-FI AP fuzzer will load the custom driver on program startup:

sudo bin/wifi_ap_fuzzer # Start fuzzer without graphical interface
Wi-Fi AP Command line options
Wi-Fi AP 802.11 Fuzzer (MAC, LLC, SNAP, EAPoL, etc)
Usage:
  Wi-Fi AP Fuzzer [OPTION...]

      --help               Print help
      --default-config     Start with default config
      --autostart          Automatically start (default: true)
      --exploit [=arg(=)]  Exploit Name
      --fuzz               Enable/Disable fuzzing (default: true)

BLE Host Fuzzer (WIP)

BLE Host fuzzer uses the same ESP32 development kit and can be run via the command

sudo bin/bthost_fuzzer # Start fuzzer without graphical interface

4) BT Exploits Usage Instructions

4.1) List Exploits

BT Fuzzer has several exploits which can be listed by running the following command:

sudo bin/bt_fuzzer --list-exploits # Run as root

Available Exploits:
--> 'invalid_timing_accuracy'
--> 'repeated_host_connection'
--> 'sdp_unkown_element_type'
--> 'knob'
--> 'invalid_feature_page_execution'
.... # And others

4.2) Scan target

Before launching the attack, you need to know the BDAddress of the target BT device. To facilitate this, BT Exploiter can scan the BDAddress of targets nearby by running the following command:

sudo bin/bt_exploiter --scan

If ESP32 is detected by bt_exploiter and scanning works, then you should get a similar output to the Figure below.

4.3) Launch the Attack!

Now it is your turn! Choose an exploit by its name and remember the target BDAddress where the exploit needs to be launched. You need to specify both the name of the exploit and the target BDAddress as follows to launch the respective attack:

sudo bin/bt_exploiter --host-port=/dev/ttyUSB1 --target=<target bdaddress> --exploit=<exploit name>

The argument --target is your target BDAddress and --host-port must match with the correct ESP32-WROVER-KIT serial port.

For example, launching the exploit for LMP AU Rand Flooding (au_rand_flooding) can be accomplished as follows:

sudo bin/bt_exploiter --host-port=/dev/ttyUSB1 --target=a4:50:46:59:0c:90 --exploit=au_rand_flooding

If the target is vulnerable, then you should get some anomalous behavior from the target (shutdown, reboot, etc) or simply not be able to discover it anymore when scanning for BT targets again.

An example of a successful attack output for a vulnerable target that shuts down after the attack is presented below.

<img src="./docs/example_attack.png" style="zoom:50%;" />

5) Create your own Exploit Scripts

The source code of all exploits (C/C++) is included in folder modules/exploits. Any change to an existing exploit or new file that you add in this folder will be automatically identified and compiled the next time you run bt_fuzzer or bt_exploiter.

For more details on how to create BT exploits, please read exploit_modules_tutorial.pdf included in this repository.

exploiter

:page_facing_up: ​Logging: Opening the capture files in Wireshark

The exploit tool includes a standalone version of Wireshark which already includes a plugin to read the customized captures saved by our tool.

Capture files are automatically saved in folder logs/Bluetooth/capture_bluetooth.pcapng. To open it via the custom Wireshark, run the following on the root folder of the exploiter (bin folder must be present on your working directory):

./bin/wireshark logs/Bluetooth/capture_bluetooth.pcapng

You should see the following if the capture file was generated correctly:

wireshark

☢️ Full List of BT Exploits

The detailed table of attacks is shown below.

CVE IDAttack NameAffected Vendor(s)Affected SoC(s) or Product(s)ImpactExploit Name
CVE-2021-28139Feature Page ExecutionEspressif SystemsESP32 (SoC)ACE / Deadlockinvalid_feature_page_execution
CVE-2021-28136Duplicated IOCAPEspressif SystemsESP32 (SoC)Crash (Reboot)duplicated_iocap
CVE-2021-28135Feature Res. FloodingEspressif SystemsESP32 (SoC)Crash (Reboot)feature_response_flooding
CVE-2021-28138Invalid Public KeyEspressif SystemsESP32 (SoC)Crash (Reboot)wrong_encapsulated_payload
CVE-2021-28137Feature Req. Ping-PongEspressif SystemsESP32 (SoC)Crash (Reboot)feature_req_ping_pong
CVE-2021-28155Feature Res. FloodingHarman InternationalJBL TUNE500BT (Product)Crash (Shutdown)feature_response_flooding
CVE-2021-31609LMP Auto Rate OverflowSilabsWT32i (SoC)Crash (Reboot)lmp_auto_rate_overflow
CVE-2021-34147Invalid Timing AccuracyInfineon Technologies<br />(Former Cypress)CYW20735B1 (SoC)Crash (Reboot)invalid_timing_accuracy
CVE-2021-34146AU Rand. FloodingInfineon Technologies<br />(Former Cypress)CYW20735B1 (SoC)Crash (Reboot)au_rand_flooding
CVE-2021-34145LMP Invalid Max Slot TypeInfineon Technologies<br />(Former Cypress)CYW20735B1 (SoC)Crash (Reboot)invalid_max_slot
CVE-2021-34148LMP Max Slot OverflowInfineon Technologies<br />(Former Cypress)CYW20735B1 (SoC)Crash (Reboot)lmp_max_slot_overflow
CVE-2021-34149AU Rand. FloodingTexas InstrumentsCC2564C (SoC)Deadlockau_rand_flooding
CVE-2021-31610AU Rand. FloodingBluetrumBT889X / AB5XX / AB5301A (SoCs)Crash (Reboot)au_rand_flooding
CVE-2021-34150LMP Length Overflow over DM1BluetrumAB5301A (SoC)Deadlock (Paging disabled)lmp_overflow_dm1
CVE-2021-34143AU Rand. FloodingZhuhai Jieli TechnologyAC6366C (SoC)Deadlockau_rand_flooding
CVE-2021-34144Truncated SCO Link RequestZhuhai Jieli TechnologyAC6366C (SoC)Deadlocktruncated_sco_link_request
CVE-2021-31612LMP Auto Rate OverflowZhuhai Jieli TechnologyAC6905X (SoC)Deadlocklmp_auto_rate_overflow
CVE-2021-31613Truncated LMP_acceptedZhuhai Jieli TechnologyAC6905X / AC6925C (SoC)Crash (Reboot)truncated_lmp_accepted
CVE-2021-31611Invalid Setup CompleteZhuhai Jieli TechnologyAC6905X / AC6925C (SoC)Deadlockinvalid_setup_complete
CVE-2021-31787Feature Res. FloodingActions TechnologyATS2815 / ATS2819 (SoC)Crash (Shutdown)feature_response_flooding
CVE-2021-31785Repeated Host ConnectionActions TechnologyATS2815 / ATS2819 (SoC)Deadlockrepeated_host_connection
CVE-2021-31786Multiple Same Host ConnectionActions TechnologyATS2815 / ATS2819 (SoC)Deadlock (Shutdown)N.A (Specific BDAddress Configuration)
CVE-2021-33155LMP Paging Scan DisableIntelIntel AX200 (SoC)Deadlock (Paging disabled)paging_scan_disable
CVE-2021-33139Invalid Timing AccuracyIntelIntel AX200 (SoC)Crash (FW Reboot)invalid_timing_accuracy
CVE-2021-30348Invalid Timing AccuracyQualcommSnapdragon 845 / 855 / Others (SoCs)Crash (FW Reboot)invalid_timing_accuracy
CVE-2021-35093LMP Length Overflow over 2-DH1QualcommCSR 8811 / CSR 8510 (SoCs)Deadlock / Crashlmp_overflow_2dh1
PendingLMP Invalid TransportBekenBK3266Deadlock (Paging disabled)lmp_invalid_transport
CVE-2019-9506 KNOB (Extra - For testing only)ManyIntel AX200 (SoC)Encryption Downgradeknob

:email: ​Supported BT Protocol Stacks

WDissector is built upon well known protocols stack implementation. These are used to generate messages and to guide the target device towards a set of protocol procedures which are expected to be tested again unknown or insecure behaviour.

BT Stack

☁️ Web API

The fuzzer starts a SocketIO server and exposes access to its functions to a SocketIO client through websockets. The Table below lists the current API available for the client. More to be added in future updates.

Two types of server is available. You can choose the server type on the configuration file by changing the ServerModule index number:

"ServerOptions": {
    "APINamespace": "/", 			// Namespace (root path) of event. On REST, this path serves a basic API documentation
    "Enable": true,					// Enable Server
    "EnableEvents": false,  		// Enable SocketIO Asynchronous events (from server to clients)
    "ListenAddress": "127.0.0.1", 	// Server address
    "Logging": false,				// Enable Server logging
    "Port": 3000,					// Server port
    "ServerModule": 1,				// Server module index
    "ServerModulesList": [			// List of Server modules (from 0 to N)
        "SocketIOServer",			// modules/server/SocketIOServer.py (index 0)
        "RESTServer"				// modules/server/RESTServer.py     (index 1)
    ]
}

[!WARNING] SocketIO and REST Server events name are case sensitive. Requests from clients with wrong event names are ignored.

Request Events (Polling - SocketIOServer / RESTServer)

The following python script is loaded at runtime by Braktooth to interact with the C++ code:

Event NameDescriptionInputReturnExample (SocketIO)
<small>Summary</small><small>Returns summary of current fuzzing session, including statistics such as number of packets tarnsmitted and received</small><small>Nothing</small><small>String</small><small>scripts/server_test.py -r Summary</small>
<small>GraphDot</small><small>Returns current state machine in dot string format</small><small>Nothing</small><small>String</small><small>scripts/server_test.py -r GraphDot</small>
<small>GetModelConfig</small><small>Get fuzzer configuration</small><small>Nothing</small><small>JSON</small><small>scripts/server_test.py -r GetModelConfig</small>
<small>SetModelConfig</small><small>Set fuzzer configuration, returns parsing status</small><small>JSON</small><small>Boolean</small><small>scripts/server_test.py -r SetModelConfig -d '{"config":{...}}'</small>
<small>GetDefaultConfig</small><small>Get fuzzer default configuration</small><small>Nothing</small><small>JSON</small><small>scripts/server_test.py -r GetDefaultConfig</small>
<small>ResetConfig</small><small>Reset fuzzer configuration to default. Requires restart</small><small>Nothing</small><small>JSON</small><small>scripts/server_test.py -r ResetConfig</small>
<small>Shutdown</small><small>Shutdown fuzzer (terminate process)</small><small>Nothing</small><small>Nothing</small><small>scripts/server_test.py -r Shutdown</small>
<small>Start</small><small>Starts fuzzing the target defined in configuration file</small><small>Nothing</small><small>Nothing</small><small>scripts/server_test.py -r Start</small>
<small>Stop</small><small>Stops fuzzing</small><small>Nothing</small><small>Nothing</small><small>scripts/server_test.py -r Stop</small>
<small>Scan</small><small>Start BT scan (Enquiry) for a fixed time of 15 seconds. Subscribe to async event Scan to get targets results as soon as they are found during scanning</small><small>Nothing</small><small>Nothing</small><small>scripts/server_test.py -r Scan</small>
<small>GetScanResults</small><small>Get scan results of all targets found during latest scanning request. Request event Scan needs to be called first</small><small>Nothing</small><small>JSON</small><small>scripts/server_test.py -r GetScanResults</small>
<small>StartExploit</small><small>Start exploit by name</small><small>String</small><small>Boolean</small><small>scripts/server_test.py -r StartExploit -d knob</small>
<small>StopExploit</small><small>Stop exploit if it was previously running</small><small>Nothing</small><small>Nothing</small><small>scripts/server_test.py -r StartExploit -d knob</small>

[!WARNING] REST Server implements GET and POST methods for all events (endpoints).

  1. For POST requests, the argument must be sent in JSON type.
  2. For GET the request data must be included in the URL the parameter ?args=

Subscription Events (Asynchronous - SocketIOServer)

The following python script is loaded at runtime by Braktooth to interact with the C++ code: wdissector/modules/server/SocketIOServer.py

Event NameDescriptionReturnExample (SocketIO)
<small>Anomaly</small><small>Returns information of anomaly (crash/deadlock/anomaly)</small><small>JSON</small><small>scripts/server_test.py -w Anomaly</small>
<small>GraphUpdate</small><small>Returns string of current state in dot format</small><small>String</small><small>scripts/server_test.py -w GraphUpdate</small>
<small>Modules</small><small>Returns modules (exploits)  status messages. The returned json object contains "level" to indicate priority (Green "G", Yellow "Y",Red "R") and "msg"  with the status text.</small><small>JSON</small><small>scripts/server_test.py -w Modules</small>
<small>Scan</small><small>Returns scanned target information while scanning is in progress. The returned json object contains target BDAddress, Name, RSSI and Class.</small><small>JSON</small><small>scripts/server_test.py -w Scan</small>

Adding new server API endpoints in C++

Adding new events to the server requires changing the fuzzer code to register new function to corresponding events. The following code example below shows how to use src/PythonServer.hpp C++ library to easily add callbacks to events and get parameters sent from clients. Note the function RegisterEventCallback requires a string as the event name and a function pointer as callback. The example uses lambda expression to allow us to declare the callback as the argument itself.

[!WARNING] While C++ SocketIO event callbacks are busy, the main Python interpreter is blocked due to the Global Interpreter Lock (GIL). As such, do not place any time consuming code inside such C++ events. Otherwise, background Python threads will not work as expected or freeze while C++ code is being executed.

#include <iostream>
#include <string>
#include "server/SocketIOServer.hpp"

using namespace std;

SockerIOServer Server; // Server Instance

// Initialize Python Runtime
if (PythonCore.init())
{
    if (Server.init("0.0.0.0", 3000)) // Server starts here on port 3000
    {
        cout << Server.TAG << "Server at " << Server.listen_address << ":" << Server.port << endl;
		
        // Register callback to client connection or disconnection
        Server.OnConnectionChange([](bool connection) {
            if (connection)
                cout << Server.TAG, "Remote Client Connected" << endl;
            else
                cout << Server.TAG, "Remote Client Disconnected" << endl;
        });
		// Example 1: No arguments (simply do not use "args")
        Server.RegisterEventCallback("Example1", [&](py::list args) {
            // Perform action to event "Example1" requested by some client
        });
		// Example 2: Read arguments (convert first argument to string from "args")
        Server.RegisterEventCallback("Example2", [&](py::list args) {
            if (args.size() > 0)
            {   // Convert first argument from arguments array "args" to string            
                string config_string = args[0].cast<string>(); 
            	// Do something ...
            }
        });
        // Example 3: Return something back to the client
        Server.RegisterEventCallback("Example3", [&](py::list args) -> string {
            // Do something ...
            return "Hello back"
        });
    }
    else
    {
        GL1R(Server.TAG, "Server failed to initialize");
    }
}

:gear: ​Advanced Configuration (Using GUI or JSON Config. File)

The BT fuzzer configuration is loaded from configs/bt_config.json with the following list of options:

Bluetooth Options

<img src="./docs/figures/gui_bt_controls.png" alt="gui_bt_controls" style="zoom:80%;" class="custom-center" />
{
    "config": {
        "Bluetooth": {
            // BT Options
            "EnableBounding": true,
            "AuthReq": 4,        
            "DisableRoleSwitch": true,
            "IOCap": 3,
            "Pin": "0000",
            "TargetBDAddress": "E0:D4:E8:19:C7:69",
            // TODO: Store a list of targets
            "TargetBDAddressList": [  
                "24:0A:C4:61:1C:1A",
                "E0:D4:E8:19:C7:69"
            ]
            // ...
     }
  // ...
}

Security Options

Driver Options

[!WARNING]
The defaults for advanced options are recommended to be used unless debugging the firmware or manually experimenting with BT.

<img src="./docs/figures/gui_bt_driver.png" alt="gui_bt_driver" style="zoom:80%;" class="custom-center" />

[!TIP] ESP32 is a common HCI device at startup, but the fuzzer enables LMP Sniffing mode for its use. This means that you can integrate this ESP32 firmware into standard HCI tests by enabling Bridge HCI and LMP Sniffing then sending raw HCI commands on the pseudo-terminal created by the fuzzer (on /dev/pts/).

[!WARNING] Low Latency Required! Intercept TX requires a high speed USB adaptor such as FT2232H. As a general rule, a good latency is below 600us.

[!TIP] RX Bypass is a powerful feature which can be used for many used besides fuzzing. Applications range from exploits, protocol compliance testing, BT experimentation, LMP debugging over-the-air, etc. This feature is quite stable.

Server Options

<img src="./docs/figures/gui_server.png" alt="gui_server" style="zoom:80%;" class="custom-center" />

The aforementioned server options are loaded from configs/bt_config.json on the following attributes:

{
    "config": {
        // ...
        "ServerOptions": {
            "Enable": true,
            "EnableEvents": true,
            "ListenAddress": "0.0.0.0",
            "Logging": false, 			// Allows server script to print log messages
            "Port": 3000,
            "Type": "SocketIO"
        },
      // ...
    }
}

Fuzzing Options

<img src="./docs/figures/gui_fuzzing.png" alt="gui_fuzzing" style="zoom:80%;" class="custom-center" />

The aforementioned fuzzing options are loaded from configs/bt_config.json on the following attributes:

{
    "config": {
 		// ...
        "Fuzzing": {
            "DefaultDuplicationProbability": 0.3,
            "DefaultMutationProbability": 0.2,
            "MaxDuplicationTime": 4000,
            "PacketRetry": true,
            "PacketRetryTimeoutMS": 1000,
            "enable_duplication": false,
            "enable_mutation": false
        }
    // ...
}

Model Options (State Machine used during fuzzing)

<img src="./docs/figures/gui_model.png" alt="gui_model" style="zoom:80%;" class="custom-center" />

[!WARNING] When using state mapper, always remember to save your model so you can use it later via "Import Model" button. Alternativally you can save the model with the same name of BT program so it loads automatically whenever the fuzzer starts. The default model path is configs/models/bt/

:pray: ​Acknowledgement

This research was partially supported by NRF National Satellite of Excellence in Trustworthy Software Systems (Project no. RGNSOE2001 and RGNSOE2101).