Weaponizing ESP32 RF Stacks

Romain Cayre, Damien Cauquil

center

Who are we ?

Romain Cayre, EURECOM

  • maintainer of Mirage, a popular BLE swiss-army tool
  • loves cross-protocol attacks (Wazabee)

Damien Cauquil, Quarkslab

  • maintainer of Btlejack, another BLE swiss-army tool
  • loves reversing stuff, including embedded systems

Introduction

Enter the ESP32 world !

Enter the ESP32 world !

  • Cheap and lightweight SoCs

  • Commonly used for IoT devices (and DIY projects)

  • Provides WiFi, Bluetooth Low Energy / Bluetooth BR/EDR 🤩

  • Tensilica Xtensa (ESP32, ESP32-S3) and RISC-V (ESP-C3)

ESP32 global architecture

Lots of questions ...

Is it possible to:

  • sniff BLE communications ?

  • inject an arbitrary BLE PDU ?

  • divert the radio PHY to do nasty things ?

  • support other wireless protocols ?

  • turn any ESP32 into a wireless hacking tool ?

ESP32 internals

Memory Map

Memory Map

Hardware peripherals

Lots of them are mentionned in the ESP32 datasheet:

  • UART0
  • GPIO
  • SPI1
  • ...

BLE controller ?

Playing hide and seek

Playing hide and seek

Found in a pastebin somewhere:

Playing hide and seek

DA14681

BLE Link-Layer initialization

void r_lld_init()
{
    // ...
    SYNCL = 0xbed6;
    DAT_3ffb0442 = 0x8e89;
    SYNCH = 0x8e89;
    DAT_3ffb0444 = 0x5555;
    CRCINIT0 = 0x5555;
    DAT_3ffb0446 = 0x55;
    CRCINIT1 = 0x55;
    // ...
}

0x8e89bed6: the advertising access address

ESP32 BLE controller

  • 16-bit registers, like the DA14681

  • Same register order in ESP32 firmware

  • Dialog DA14681 is fully documented 😛

Fun with BLE

What are we looking for ?

  • BLE sniffing

  • Packet injection

  • Man-in-the-Middle attacks

BLE stack overview

BLE Core (DA14681 ?)

  • PHY layer

  • Handles all RF-layer operations

  • Peripheral driven by a brain

vHCI

  • Virtual Host Controller Interface

  • Used by upper BLE stacks (NimBLE or Bluedroid)

  • Standardized messages, no sniffing nor injection possible

ESP-IDF

  • Provides a compatible implementation of NimBLE and Bluedroid

  • Shipped as static libraries

  • Can be updated when ESP-IDF is updated

  • Too dependent of a specific ESP-IDF version

There is maybe a place ...

ESP32 Internal ROMs

  • 2 specific ROM regions

  • These regions contain some code and data

  • Low-level API functions to drive the BLE core 🥳

  • New problem: how to hook these functions? 🤔

Hooking ROM functions

  • ROM functions are called through r_ip_funcs_p
  • r_ip_funcs_p is a table of function pointers in RAM

Hacked functions (legit)

Let's hook !

PDU sniffing

Two main functions to hook:

  • r_lld_pdu_rx_handler(): called when a PDU is received

  • r_lld_pdu_data_tx_push(): used to send a PDU

Sniffing possible, but only for connections related to our ESP32 ☹

PDU injection

  • Use r_lld_pdu_data_tx_push() to send PDU

  • Can send data and control PDU ! 🤣

  • Needs some wrapping to work properly

Man-in-the-Middle

  • We need a deep control over the BLE core

  • Or at least to handle two different connections at the same time

  • Seems impossible to achieve with an ESP32

Some cool hacks 👌

LL_VERSION_IND injection

def send_version(self):
    """Send LL_VERSION_IND PDU.
    """
    if not self.__version_sent:
        # Mark version as sent
        self.__version_sent = True

        # Send LL_VERSION_IND PDU
        self.send_control(
            BTLE_CTRL() / LL_VERSION_IND(
                version=self.__llm.stack.bt_version,
                company=self.__llm.stack.manufacturer_id,
                subversion=self.__llm.stack.bt_sub_version
            )
        )

LL_VERSION_IND injection

Remote BLE stack fingerprinting !

Hacking the physical layer

Cross-protocol attacks

Can ESP32 radio be diverted to interact with other protocols ?

  • BLE uses Gaussian Frequency Shift Keying (GFSK) modulation...

  • ... like dozens of proprietary protocols in the same band !
    (ANT+ / ANT-FS, Riitek, MosArt, Logitech Unifying, Microsoft...)

  • WazaBee: equivalence between O-QSPK (802.15.4) and 2Mbps GFSK (BLE 2M) 🠂 ESP32-S3 / ESP32-C3 only

Cross-protocol attacks

We need to control low level radio parameters:

  • CRC verification
  • frequency
  • datarate
  • synchronization word
  • whitening / dewhitening
  • input and output bitstreams

BLE RX synchronization

Hacking synchronization

Packet Processing

Bypassing Packet Processing

BLE Packet Transmission

Packet in Packet

Let's dive deeper

BLE Core is programmed using a shared memory zone named Exchange Memory.

Exchange Memory

Frequency table

Control structures

BLE registers

RWBLECNTL Register Definition

  Bits           Field Name   Reset Value
 -----   ------------------   -----------
    31      MASTER_SOFT_RST   0
    30    MASTER_TGSOFT_RST   0
    29         REG_SOFT_RST   0
    28            SWINT_REQ   0
    26         RFTEST_ABORT   0
    25         ADVERT_ABORT   0
    24           SCAN_ABORT   0
    22               MD_DSB   0
    21               SN_DSB   0
    20             NESN_DSB   0
    19            CRYPT_DSB   0
    18             WHIT_DSB   0
    17              CRC_DSB   0
    16        HOP_REMAP_DSB   0
    09        ADVERTFILT_EN   0
    08             RWBLE_EN   0
 07:04           RXWINSZDEF   0x0
 02:00              SYNCERR   0x0

Arbitrary reception primitive

  • Hook r_llm_start_scan_en() and modify RF parameters:

    • Frequency Table: alter frequency of channel 39
    • Control Structure: force channel 39, disable channel hopping, configure synchronization word, datarate and test format
    • Global Registers: disable whitening and CRC
  • Reuse r_lld_pdu_rx_handler() hook to extract packets

Arbitrary transmission primitive

  • Hook r_lld_pdu_tx_push and modify RF parameters

  • Find the TX buffer in EM and write a packet (PIP attack)

  • Start radio in TX test mode

Demo time !

Can we go deeper ?

RF imperfections

RF imperfections related to transceiver architecture


Mismatch between In-phase (I) and In-quadrature (Q) paths

Calibration process

Imperfections corrected using digital calibration technique:

Loopback between TX and RX path to estimate and compensate I/Q mismatch.

Forcing a full calibration

Calibration data stored in Non Volatile Memory (NVM).
Full calibration only triggered if calibration data can't be found !

// Disable both Bluetooth and Radio Module
esp_bt_controller_shutdown();

// Flush calibration data
esp_phy_erase_cal_data_in_nvs();

// Enabling Radio Module to force a new calibration
esp_phy_enable();

Hooking PHY functions


PHY functions stored in a specific function pointers array: g_phyFuns (pointer returned byphy_get_romfuncs())

Diverting calibration process

  • Disable HW frequency control (phy_dis_hw_set_freq)
  • Infinite loop when rom_loopback_mode_en is called
  • Have fun with signal control functions (frequency, gain) !

Fun with signals

WiFi Jamming

BLE Jamming

BLE Jamming - demo

Q/A time

Thank you !

Capture is a screenshot from Ghidra. These functions have been found in a firmware compiled with Espressig SDK, and are 100% related to BLE. Let's dig up a bit ...

Looks like it is a DA14681 BLE stack ?! Dafuq ?