Matheus-Garbelini / braktooth_esp32_bluetooth_classic_attacks

A Series of Baseband & LMP Exploits against Bluetooth Classic Controllers
https://braktooth.com
445 stars 85 forks source link

BrakTooth Proof of Concept Attacks (+ BT Fuzzing Framework)

mode_master

mode_master

[!TIP]

  • 31/08/2024 - New Braktooth experimental release supports ARM64. It at least it runs on it! You can download in the releases page.


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.

The recommended hardware is ESP-WROVER-KIT-VE. 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.

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 ID Attack Name Affected Vendor(s) Affected SoC(s) or Product(s) Impact Exploit Name
CVE-2021-28139 Feature Page Execution Espressif Systems ESP32 (SoC) ACE / Deadlock invalid_feature_page_execution
CVE-2021-28136 Duplicated IOCAP Espressif Systems ESP32 (SoC) Crash (Reboot) duplicated_iocap
CVE-2021-28135 Feature Res. Flooding Espressif Systems ESP32 (SoC) Crash (Reboot) feature_response_flooding
CVE-2021-28138 Invalid Public Key Espressif Systems ESP32 (SoC) Crash (Reboot) wrong_encapsulated_payload
CVE-2021-28137 Feature Req. Ping-Pong Espressif Systems ESP32 (SoC) Crash (Reboot) feature_req_ping_pong
CVE-2021-28155 Feature Res. Flooding Harman International JBL TUNE500BT (Product) Crash (Shutdown) feature_response_flooding
CVE-2021-31609 LMP Auto Rate Overflow Silabs WT32i (SoC) Crash (Reboot) lmp_auto_rate_overflow
CVE-2021-34147 Invalid Timing Accuracy Infineon Technologies
(Former Cypress)
CYW20735B1 (SoC) Crash (Reboot) invalid_timing_accuracy
CVE-2021-34146 AU Rand. Flooding Infineon Technologies
(Former Cypress)
CYW20735B1 (SoC) Crash (Reboot) au_rand_flooding
CVE-2021-34145 LMP Invalid Max Slot Type Infineon Technologies
(Former Cypress)
CYW20735B1 (SoC) Crash (Reboot) invalid_max_slot
CVE-2021-34148 LMP Max Slot Overflow Infineon Technologies
(Former Cypress)
CYW20735B1 (SoC) Crash (Reboot) lmp_max_slot_overflow
CVE-2021-34149 AU Rand. Flooding Texas Instruments CC2564C (SoC) Deadlock au_rand_flooding
CVE-2021-31610 AU Rand. Flooding Bluetrum BT889X / AB5XX / AB5301A (SoCs) Crash (Reboot) au_rand_flooding
CVE-2021-34150 LMP Length Overflow over DM1 Bluetrum AB5301A (SoC) Deadlock (Paging disabled) lmp_overflow_dm1
CVE-2021-34143 AU Rand. Flooding Zhuhai Jieli Technology AC6366C (SoC) Deadlock au_rand_flooding
CVE-2021-34144 Truncated SCO Link Request Zhuhai Jieli Technology AC6366C (SoC) Deadlock truncated_sco_link_request
CVE-2021-31612 LMP Auto Rate Overflow Zhuhai Jieli Technology AC6905X (SoC) Deadlock lmp_auto_rate_overflow
CVE-2021-31613 Truncated LMP_accepted Zhuhai Jieli Technology AC6905X / AC6925C (SoC) Crash (Reboot) truncated_lmp_accepted
CVE-2021-31611 Invalid Setup Complete Zhuhai Jieli Technology AC6905X / AC6925C (SoC) Deadlock invalid_setup_complete
CVE-2021-31787 Feature Res. Flooding Actions Technology ATS2815 / ATS2819 (SoC) Crash (Shutdown) feature_response_flooding
CVE-2021-31785 Repeated Host Connection Actions Technology ATS2815 / ATS2819 (SoC) Deadlock repeated_host_connection
CVE-2021-31786 Multiple Same Host Connection Actions Technology ATS2815 / ATS2819 (SoC) Deadlock (Shutdown) N.A (Specific BDAddress Configuration)
CVE-2021-33155 LMP Paging Scan Disable Intel Intel AX200 (SoC) Deadlock (Paging disabled) paging_scan_disable
CVE-2021-33139 Invalid Timing Accuracy Intel Intel AX200 (SoC) Crash (FW Reboot) invalid_timing_accuracy
CVE-2021-30348 Invalid Timing Accuracy Qualcomm Snapdragon 845 / 855 / Others (SoCs) Crash (FW Reboot) invalid_timing_accuracy
CVE-2021-35093 LMP Length Overflow over 2-DH1 Qualcomm CSR 8811 / CSR 8510 (SoCs) Deadlock / Crash lmp_overflow_2dh1
Pending LMP Invalid Transport Beken BK3266 Deadlock (Paging disabled) lmp_invalid_transport
CVE-2019-9506 KNOB (Extra - For testing only) Many Intel AX200 (SoC) Encryption Downgrade knob

: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 Name Description Input Return Example (SocketIO)
Summary Returns summary of current fuzzing session, including statistics such as number of packets tarnsmitted and received Nothing String scripts/server_test.py -r Summary
GraphDot Returns current state machine in dot string format Nothing String scripts/server_test.py -r GraphDot
GetModelConfig Get fuzzer configuration Nothing JSON scripts/server_test.py -r GetModelConfig
SetModelConfig Set fuzzer configuration, returns parsing status JSON Boolean scripts/server_test.py -r SetModelConfig -d '{"config":{...}}'
GetDefaultConfig Get fuzzer default configuration Nothing JSON scripts/server_test.py -r GetDefaultConfig
ResetConfig Reset fuzzer configuration to default. Requires restart Nothing JSON scripts/server_test.py -r ResetConfig
Shutdown Shutdown fuzzer (terminate process) Nothing Nothing scripts/server_test.py -r Shutdown
Start Starts fuzzing the target defined in configuration file Nothing Nothing scripts/server_test.py -r Start
Stop Stops fuzzing Nothing Nothing scripts/server_test.py -r Stop
Scan 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 Nothing Nothing scripts/server_test.py -r Scan
GetScanResults Get scan results of all targets found during latest scanning request. Request event Scan needs to be called first Nothing JSON scripts/server_test.py -r GetScanResults
StartExploit Start exploit by name String Boolean scripts/server_test.py -r StartExploit -d knob
StopExploit Stop exploit if it was previously running Nothing Nothing scripts/server_test.py -r StartExploit -d knob

[!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 Name Description Return Example (SocketIO)
Anomaly Returns information of anomaly (crash/deadlock/anomaly) JSON scripts/server_test.py -w Anomaly
GraphUpdate Returns string of current state in dot format String scripts/server_test.py -w GraphUpdate
Modules 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. JSON scripts/server_test.py -w Modules
Scan Returns scanned target information while scanning is in progress. The returned json object contains target BDAddress, Name, RSSI and Class. JSON scripts/server_test.py -w Scan

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

gui_bt_controls
{
    "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.

gui_bt_driver

[!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

gui_server

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

gui_fuzzing

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)

gui_model

[!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).