Hacking Bluetooth fácil con ESP32, HCI y comandos ocultos
Ya tenemos una metodología de seguridad Bluetooth, pero siguen faltando herramientas con las cuales poder auditar y hacer pruebas de seguridad
Después de mucho tiempo realizando auditorías Bluetooth, en el 2021, debido a la falta de información y a la dispersión de esta, decidimos iniciar una línea de investigación sobre Bluetooth.
Tras el primer año publicamos nuestro primer ataque, llamado BlueTrust, mediante el cual se pueden obtener las relaciones de confianza entre dispositivos Bluetooth, aunque no estuviesen todos presentes en el mismo lugar. Este tiempo también sirvió para darnos cuenta de que era necesario agrupar la información disponible sobre la seguridad de Bluetooth, y esto dio como resultado BSAM, una metodología libre y abierta similar a OWASP pero para Bluetooth que nos facilita el proceso de auditoría de un dispositivo.
Después de otro año más investigando, seguíamos teniendo la sensación de que siguen faltando más cosas…
Para que nos pongamos en contexto, en el 2024 se han publicado 30 ataques o noticias (https://darkmentor.com/bt.html) relacionados con la seguridad en Bluetooth. De estos, únicamente 7 tienen pruebas de concepto públicas. De estos 7, solo 3 se pueden implementar con hardware estándar, y solo una es compatible con varios sistemas operativos.
Si vamos más atrás en el tiempo y no solo miramos el 2024, con respecto a herramientas, con un vistazo rápido en Github podemos ver las herramientas relacionadas con Bluetooth y ataques.
Vemos que hay herramientas, pero que la gran mayoría no están mantenidas o tienen muchos issues o pull request que no se solucionan y por lo general obsoletas, es decir, tienen más de tres años, por lo que se hace difícil compilarlas o ejecutarlas con las APIs y versiones de librerías y SDKs actuales.
Si nos centramos en el hardware, por un lado, tenemos hardware multipropósito, como puede ser el Flipper Zero, M5Stack, CapibaraZero, con un panorama variado. Este hardware multipropósito orientado a la auditoría de seguridad, no solo de Bluetooth, nos ofrece demasiadas alternativas a elegir entre ellos y no cubren todas las necesidades del mercado, es decir, no permiten funcionalidades a bajo nivel y los ataques a nivel de Bluetooth son muy básicos, spam de paquetes de advertisement y poco más.
Si lo vemos desde el punto de vista de hardware más genérico como pueden ser dongles USB y orientado a nuestros PCs la situación no mejora.
De nuevo, muchas implementaciones, dependencia del modelo de chip utilizado, los costes de compra de tantos dispositivos son elevados y cubren necesidades muy distintas entre ellos. Para desarrollar una herramienta de seguridad y auditoría Bluetooth no existen muchas opciones.
APIs de alto nivel que limitan la funcionalidad a servicios Bluetooth e ignoran los procesos de bajo nivel como pairing o descubrimiento.
APIs a bajo nivel que son dependientes del sistema operativo si es que este lo permite, estas sanean parte de la entrada de datos limitando a las acciones a las que establece el estándar y también son inconsistentes entre OS, pudiendo devolver resultados diferentes dependiendo de donde se ejecute ya que utilizan distintas implementaciones dependiendo del stack o framework usado.
Y después, cada sistema operativo tiene su propio stack, lo cual hace inviable desarrollar en una plataforma y portarlo a otra de una manera sencilla. Ya disponemos de una guía a seguir para poder auditar un dispositivo Bluetooth al detalle, pero se necesita un marco común que permita simplificar el desarrollo de herramientas.
- Que no sea dependiente del sistema operativo.
- Que pueda usar cualquier hardware o que no sea dependiente de este.
- Y que se puedan hacer en el lenguaje de programación de tu elección.
- Y que tu única tarea sea pelearte con las especificaciones de Bluetooth, de más de 4000 paginas.
Por eso, lo que parece es que necesitamos alguna manera universal para poder interactuar con el hardware Bluetooth.
Vamos a hacer un breve recordatorio de cómo funciona Bluetooth de una manera y a muy alto nivel.
Bluetooth se compone de dos componentes, el host, que es el software que gestiona las conexiones y los datos y el controller, que es el chip que corre un firmware y se encarga de gestionar los paquetes inalámbricos.
Para simplificarlo mucho, digamos que el host es tu ordenador que ejecuta acciones a alto nivel, y se comunica con el controller, que es el chip que se encarga de enviar paquetes, mantener la conexión, etc.
El software del host y el controller se comunican a través del protocolo HCI, donde se van encapsulando y anidando protocolos dentro de paquetes. Este protocolo es estándar independiente del sistema operativo y funciona sobre USB y UART/Serial.
Sabiendo esto, parece que lo que hace falta es algún tipo de driver HCI que se pueda correr en cualquier sitio y se pueda utilizar desde cualquier lenguaje de programación. El resultado de todo esto es USB Bluetooth. Se trata de un driver HCI, escrito en C, independiente de la plataforma e independiente del hardware.
Este driver se publica Open Source para que sea accesible por y para todos. El driver funciona mediante el acceso directo al hardware Bluetooth usando WinUSB y libusb.Además, cuenta con bindings para Python y C# para extender el soporte a otros lenguajes de programación, facilitando el desarrollo de herramientas de manera sencilla.
En el caso de Python, también hacemos disponible un paquete que permite hacer uso de USB Bluetooth en Scapy facilitando la construcción e interpretación de paquetes Bluetooth.
De esta manera contamos con un driver independiente de la plataforma, con soporte para varios lenguajes y que nos permite interactuar con nuestro hardware sin restricciones y sin interferencia del sistema operativo.
Este driver nos permite implementar herramientas que hacen uso de la funcionalidad estándar del controlador como escáneres de dispositivos o automatización de pruebas de conexión y pairing.
También permite construir herramientas que requieren la utilización de paquetes HCI malformados como crear fuzzers, ya que este driver no comprueba la integridad de los paquetes HCI que se envían al controlador Bluetooth. Entre las limitaciones de este driver se encuentra el no poder escapar al comportamiento habitual del controlador y la necesidad de hardware específico para implementar ataques avanzados que requieran esta capacidad.
También es importante advertir que muchos controladores Bluetooth integrados en portátiles incluyen funcionalidad WiFi y Bluetooth, por lo que si usamos ese adaptador es probable que perdamos la conectividad WiFi de nuestra máquina. Por ello, se recomienda el uso de hardware externo con este driver.
¿Qué hardware Bluetooth usar?
Ahora que parece que tenemos resuelto el tema de cómo desarrollar software, ¿qué se puede hacer con el hardware?
Pues idealmente estaría bien contar con un hardware que:
- Esté disponible y no se agote el stock fácilmente, cosa que no pasa con placas de desarrollo.
- Que se pueda comprar en cualquier país.
- Y ya puestos a pedir, que sea barato.
Y como última nota en la carta de deseos, que soporte tanto Classic como Low Energy.
Si volvemos al hardware multipropósito que nombramos antes y que se usa entre otras cosas para hacking inalámbrico Bluetooth y wifi, salvo el Flipper Zero vemos que está desarrollado con el chip ESP32 y existen múltiples proyectos que lo usan: ESP32Marauder, Ghost ESP, Bruce y muchos más. También existen muchas placas que montan es este chip tanto para incluir en tus desarrollos hardware como con conector USB, a precios muy bajos y disponibles en prácticamente todo el mundo.
Hablamos de un coste de un par de euros por un chip que soporta Bluetooth Classic, LE, WiFi y en algunos casos ZigBee, por esto no es de extrañar que esté en tantos proyectos. Por este motivo creímos que era un buen candidato para ver si se podía usar como hardware avanzado y poder implementar herramientas que usen el protocolo Bluetooth a más bajo nivel.
Analizando que se puede hacer a día de hoy a nivel de Bluetooth con el ESP32, como lo usan los proyectos existentes y ver qué se puede mejorar.
Por lo general, se usan firmwares personalizados con los cuales se flashea el dispositivo. Estos firmwares especializados se centran en realizar una sola función, normalmente haciendo que deje de ser compatible con otras funcionalidades como trabajar como una tarjeta genérica de Bluetooth para el PC. También se requieren conocimientos para programar los dispositivos y la complejidad de desarrollar parches puede afectar a la estabilidad del firmware del dispositivo, ya que únicamente se proporciona en binario y hay que modificarlo ahí.
Durante el último año hemos hecho un esfuerzo de ingeniería inversa en el firmare del ESP, centrados en la parte de radio Bluetooth.
Para esto se ha recopilado el código a analizar que puede ayudar a lograr nuestro objetivo. Por una parte, Espressif facilita las ROMs internas del dispositivo en formato ELF. Esto facilita el trabajo de ingeniería inversa ya que los ficheros incluso incluyen algunos nombres de símbolos. También se recopilan las librerías relacionadas con Bluetooth o comunicaciones inalámbricas disponibles en el SDK en formato binario disponibles en GitHub.
Para el análisis de librerías se ha optado por generar un golden binary unificándolas en un solo archivo para evitar realizar el análisis por separado y tener que definir la relación entre los distintos archivos. Para esto se ha usado el propio linker de ESP32 con la opción whole archive para evitar que este optimice el código y quite secciones no usadas.
PS C:\> xtensa-esp32-elf-ld -r -o golden_bin.elf --whole-archive .\libbtdm_app.a .\libbttestmode.a .\libphy.a .\librftest.a .\librtc.a PS C:\> ls .\golden_bin.elf Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 25/02/2025 9:17 4156284 golden_bin.elf
Para que las aplicaciones de ESP32 puedan llamar a las funciones internas de la ROM del chip, el compilador necesita saber dónde se ubican estas funciones. Para ello, Espressif publica unos linker scripts que contienen listas de símbolos y sus direcciones simplificando proceso de ingeniería. Y se ha publicado un plugin de Ghidra que permite incorporar esta información a los ficheros a analizar.
Finalmente, cabe destacar que gran parte del código analizado lee y escribe de regiones de memoria estáticas del chip. Estas direcciones son utilizadas para controlar los periféricos que son componentes del chip que nos permiten interactuar con el exterior e intercambiar información con otros chips.
El datasheet del ESP32 contiene información sobre estas regiones de memoria, pero esta información no es muy muy abundante y además es muy tediosa de incorporar a mano en los programas de ingeniería inversa. Por suerte, Espressif también publica archivos SVD que documentan precisamente esto en https://github.com/espressif/svd y https://github.com/esp-rs/esp-pacs/tree/main/esp32/svd. SVD es un estándar basado en XML y originalmente concebido para ARM pero que se ha extendido por su utilidad para documentar información sobre chips de manera que otras herramientas puedan generar código o facilitar labores de depuración.
Ghidra no soporta nativamente importar este tipo de ficheros, pero existen plugins que permiten incorporar la información (https://github.com/antoniovazquezblanco/GhidraSVD).
Una vez ya recopilada toda esta información, procedemos a analizar los ficheros. Encontramos que el ESP32 se programa con FreeRTOS. Siguiendo las llamadas de inicialización del código de Bluetooth descubrimos que no es el único RTOS que ejecuta este dispositivo.
Más concretamente, siguiendo las funciones de inicialización de Bluetooth llegamos a una función llamada RWIP_INIT. Ese prefijo RW en muchas funciones nos da indicios de que parte del hardware ha podido ser desarrollado por RivieraWaves con lo que este RTOS/Kernel puede que también tenga ese origen.
Continuando el análisis, en esta misma función encontramos una función que hace referencia a H4 Transport layer. H4 hace referencia a la capa de transporte HCI. Es un término que se usaba en las primeras versiones del estándar de Bluetooth para referirse a HCI. Si miramos en detalle esta función H4 INIT, en ella se establecen un par de callbacks que se ejecutarán cuando se hayan recibido paquetes HCI. Analizando los callbacks llegamos a una función que consulta una tabla en memoria que indica qué se debe ejecutar para cada paquete. Las tablas a su vez contienen subtablas y se encuentran separadas por un campo llamado OGF (Opcode Group Field) documentado en el estándar de Bluetooth. Como ejemplo, el grupo 1 se corresponde con la sección Link Control.
La última entrada hace referencia al grupo 0x3f, que se trata de un grupo reservado para comandos propietarios de un fabricante, de los cuales no hay constancia en la documentación ni en publicaciones anteriores.
Si vamos a la subtabla nos encontramos con 29 comandos no documentados en ninguna parte. Descubrimos los opcodes de cada uno de esos 29 comandos ocultos y para qué sirve cada uno de ellos.
Opcode | Command |
OxFC01 | Read memory |
OxFC02 | Write memory |
OxFC03 | Delete NVDS parameter |
OxFC05 | Get flash ID |
OxFC06 | Erase flash |
OxFC07 | Write flash |
OxFC08 | Read flash |
OxFC09 | Read NVDS parameter |
OxFC0A | Write NVDS parameter |
OxFC0B | Enable/disable coexistence |
OxFC0E | Send LMP packet |
OxFC10 | Read kernel stats |
OxFC11 | Platform reset |
OxFC12 | Read memory info |
OxFC30 | Register read |
OxFC31 | Register write |
OxFC32 | Set MAC address |
OxFC35 | Set CRC initial value |
OxFC36 | LLCP msgs discard |
OxFC37 | Reset RX count |
OxFC38 | Reset TX count |
OxFC39 | RF register read (Not implemented) |
OxFC3A | RF register write (Not implemented) |
OxFC3B | Set TX password |
OxFC40 | Set LE parameters |
OxFC41 | Write LE default values |
OxFC42 | LLCP pass through enable |
OxFC43 | Send LLCP packet |
OxFC44 | LMP msgs discard |
Los comandos permiten prácticamente de todo. Desde leer registros de la CPU, enviar paquetes de las capas de Bluetooth, leer estadísticas del kernel propietario, cambiar la MAC del dispositivo y mucho más.
¿Para qué nos sirve todo esto?
Podemos controlar el hardware del ESP32 de maneras no previstas, usando código proporcionado por Espressif, sin necesidad de personalizar el firmware o de aplicar parches que pueden ser complicados de mantener o gestionar.
Concretamente destaca la funcionalidad de cambiar la MAC del dispositivo, a pesar de ser muy simple, da mucha versatilidad para ampliar la superficie de ataque ya que nos permite suplantar a otros dispositivos.
Para los ataques más avanzados, en lugar de personalizar el firmware, podemos hacer uso de los comandos que nos permiten acceder a los protocolos de bajo nivel de Bluetooth.
¿Desde el punto de la ciberseguridad que usos se le pueden dar a estos hallazgos del ESP32?
En ocasiones, el chip ESP32 es usado únicamente como chip de comunicaciones y la lógica del dispositivo se gestiona desde otro procesador, donde las funcionalidades del dispositivo corren en un procesador principal, posiblemente ARM, y el ESP32 es únicamente usado como tarjeta y chip de comunicaciones Bluetooth y WiFi.
En este caso de uso, entre muchas otras cosas, podemos cambiar la MAC, estamos en disposición de acceder a la memoria del ESP32, tanto lectura como escritura a través de comandos HCI, que también nos dan acceso a tráfico de Bluetooth de bajo nivel, que da pie a implementar y portar ataques que requiere funcionalidades avanzada del chip.
Con esto en mente, para cualquier dispositivo en el cual podamos enviar comandos HCI podemos implementar ataques avanzados de Bluetooth, es decir, cualquier dispositivo IOT con ESP32 es un potencial dispositivo desde el cual poder realizar ataques
En el caso de que podamos ejecutar código en un dispositivo IOT que use el ESP32 como módulo de comunicaciones, por un fallo de seguridad mediante el cual el dispositivo IOT se vea comprometido, haciendo uso de comandos HCI se puede almacenar código en la memoria del ESP32 y ejecutarlos de manera oculta al procesador principal, y no solo eso, esta escritura es persistente. Esto hace que teniendo acceso legítimo o vulnerando un dispositivo IOT que use el ESP32 como módulo de comunicaciones a través de HCI, se puede conseguir persistencia, ejecutar código, realizar ataques Bluetooth, rastrear y seguir dispositivos y exfiltrar información mediante Bluetooth o WiFi.
Si bien no se trata de una vulnerabilidad remota del Bluetooth y estas funcionalidades ocultas, presentes en el firmware, se pueden utilizar como medio para inyectar código persistente que realice actividades o comportamientos maliciosos desde cualquier dispositivo que use el ESP32 como chip de comunicaciones HCI.
Conclusión:
En estos momentos ya tenemos:
- Una metodología que nos ayuda a tener una guía a seguir a la hora de analizar la seguridad de un dispositivo Bluetooth.
- Una manera de desarrollar software fácilmente, portable y que permite usar tu lenguaje de programación favorito.
- Integraciones con librerías como Scapy.
- Un hardware barato mediante el cual podemos implementar todos los ataques existentes y que nos proporciona el punto de partida sobre el cual seguir desarrollando herramientas.
Adicionalmente se han evidenciado maneras de cómo usar estos comandos ocultos que permiten funcionalidades avanzadas para permitir acceso directo y completo a la memoria y ejecución del ESP32 desde cualquier hardware que haga uso de este chip a través de HCI así como persistencia. Durante los próximos días se publicarán artículos técnicos con toda la documentación, código y ejemplos.