Romain Cayre, EURECOM
Damien Cauquil, Quarkslab
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)
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 ?
Lots of them are mentionned in the ESP32 datasheet:
UART0
GPIO
SPI1
Found in a pastebin somewhere:
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
16-bit registers, like the DA14681
Same register order in ESP32 firmware
Dialog DA14681 is fully documented
BLE sniffing
Packet injection
Man-in-the-Middle attacks
PHY layer
Handles all RF-layer operations
Peripheral driven by a brain
Virtual Host Controller Interface
Used by upper BLE stacks (NimBLE or Bluedroid)
Standardized messages, no sniffing nor injection possible
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
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?
r_ip_funcs_p
Two main functions to hook:
r_lld_pdu_rx_handler(): called when a PDU is received
r_lld_pdu_rx_handler()
r_lld_pdu_data_tx_push(): used to send a PDU
r_lld_pdu_data_tx_push()
Sniffing possible, but only for connections related to our ESP32
Use r_lld_pdu_data_tx_push() to send PDU
Can send data and control PDU !
Needs some wrapping to work properly
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
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 ) )
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
We need to control low level radio parameters:
BLE Core is programmed using a shared memory zone named Exchange Memory.
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
Hook r_llm_start_scan_en() and modify RF parameters:
r_llm_start_scan_en()
Reuse r_lld_pdu_rx_handler() hook to extract packets
Hook r_lld_pdu_tx_push and modify RF parameters
r_lld_pdu_tx_push
Find the TX buffer in EM and write a packet (PIP attack)
Start radio in TX test mode
RF imperfections related to transceiver architecture
Mismatch between In-phase (I) and In-quadrature (Q) paths
Imperfections corrected using digital calibration technique:
Loopback between TX and RX path to estimate and compensate I/Q mismatch.
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();
PHY functions stored in a specific function pointers array: g_phyFuns (pointer returned byphy_get_romfuncs())
g_phyFuns
phy_get_romfuncs()
phy_dis_hw_set_freq
rom_loopback_mode_en
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 ?