Comandos HCI ocultos en ESP32, detalles técnicos y casos de uso

El chip ESP32 tiene comandos HCI ocultos


 

El estándar de Bluetooth propone una separación de su arquitectura en dos componentes principales.
Por un lado, se encuentra el controller, compuesto por un hardware especializado con capacidad para implementar la capa física de radiofrecuencia y que corre un firmware encargado de las comunicaciones de bajo nivel, que requieren operaciones en tiempo real y de alta precisión.

Por otro, se encuentra el host, que es el software que se encarga de la gestión de las comunicaciones a alto nivel sin preocuparse por los detalles de los paquetes de bajo nivel y que orquesta al controller.

De manera muy simplificada, esto suele traducirse en que el host es un software ejecutado en un dispositivo, generalmente el procesador de la placa principal de un dispositivo IoT y 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 HCI es estándar independiente del sistema operativo y puede funcionar sobre USB y UART/Serial.

En particular, el chip ESP32 permite ser usado en dos configuraciones distintas:

  • Host y controller en el mismo chip, en la que la aplicación (host) se ejecuta en el mismo ESP32 y se comunica mediante una interfaz HCI virtual con el controller dentro del mismo chip.
  • Solamente como controller, en la que la aplicación se ejecuta en otro chip u ordenador y se usa el ESP32 como controller mediante una interfaz HCI a través de la UART.

En este artículo nos centraremos en la segunda configuración en la que el chip ESP32 actúa solo como un controller Bluetooth y que mediante HCI es controlado por otro chip u ordenador para ver las acciones que se podrían llevar a cabo de forma local.

El protocolo HCI se compone principalmente de dos tipos de paquetes.

  • Comandos: Los paquetes que el host envía al controller.
  • Eventos: Por lo general paquetes de respuesta a comandos, con los que el controller envía información al host.

Las comunicaciones se inician por parte del host mediante el envío de un comando y este puede tener una o varias respuestas en forma de eventos por parte del controller.

Tipo HCI

ValorSignificado
0X01Comando
0X04Evento

En el caso de un comando, esta cabecera va seguida por otra cabecera que contiene dos campos, un opcode (2 bytes) y un indicador de longitud (1 byte).

HCI Command Header

OpcodeLongitud
2 bytes1 byte

El opcode identifica el tipo de comando concreto y sirve para indicar que acción quiere realizar el host. Se trata de un valor compuesto que se puede separar en un OGF (Opcode Group Field) de 6 bits y un OCF (Opcode Command Field) de 10 bits. Es decir, el opcode está compuesto por dos partes, una primera que identifica el grupo de comandos al que pertenece y una segunda que indica el comando concreto dentro del grupo.

En el estándar de Bluetooth se reconoce un OGF dedicado a comandos propietarios de fabricante. Este es el OGF 0x3F. Todos los comandos en este grupo son implementados por el fabricante y con un formato arbitrario que puede estar documentado o no.

Mediante la ingeniería inversa de los archivos binarios de la ROM del ESP32 publicados en el SDK del chip se han identificado 29 comandos propietarios no documentados en el ESP32. Estos comandos permiten funcionalidades no contempladas mediante los comandos HCI estándar y ofrecen un mayor control sobre el controlador de Bluetooth. También son interesantes algunos comandos que habilitan el acceso a recursos internos del ESP32, como a la memoria RAM o la memoria flash. Estos últimos tienen implicaciones de seguridad, ya que permiten acceso a recursos que no se contemplan en el modelo de seguridad de las comunicaciones estándar de HCI.

También mediante ingeniería inversa se han obtenido los parámetros, su formato y el formato del evento de retorno de dichos comandos.

OpcodeCommand
0xFC01Read memory
0xFC02Write memory
0xFC03Delete NVDS parameter
0xFC05Get flash ID
0xFC06Erase flash
0xFC07Write flash
0xFC08Read flash
0xFC09Read NVDS parameter
0xFC0AWrite NVDS parameter
0xFC0BEnable/disable coexistence
0xFC0ESend LMP packet
0xFC10Read kernel stats
0xFC11Platform reset
0xFC12Read memory info
0xFC30Register read
0xFC31Register write
0xFC32Set MAC address
0xFC35Set CRC initial value
0xFC36LLCP msgs discard
0xFC37Reset RX count
0xFC38Reset TX count
0xFC39RF register read (Not implemented)
0xFC3ARF register write (Not implemented)
0xFC3BSet TX password
0xFC40Set LE parameters
0xFC41Write LE default values
0xFC42LLCP pass through enable
0xFC43Send LLCP packet
0xFC44LMP msgs discard

A continuación, se examinan algunos de los comandos encontrados que simplifican el llevar a cabo ataques Bluetooth contra terceros dispositivos, o que afectan a la seguridad del propio chip cuando existe la capacidad de ejecutar código en el host.

Set Mac Address command

CommandOCFCommand parametersReturn parameters
HCI_ESP32_CMD_SET_MAC0x32Bd_AddrStatus

Description:

Configura la dirección MAC del controlador Bluetooth.

Command Parameters:

Bd_Addr Size: 6 Octets

ValueParameter description
0xXXXXXXXXXXXXMAC Address of the device

Return Parameters:

Status Size: 1 Octet

ValueParameter description
0x00HCI_Esp32_Set_Mac_Address command succeeded.
0x01 to 0xFFHCI_Esp32_Set_Mac_Address command failed. See [Vol 1]
Part F, Controller Error Codes, for error codes and descriptions

Este comando permite modificar la dirección MAC con la que se presenta el controlador e interactúa con otros dispositivos.

Desde el punto de vista de la seguridad, la suplantación de dirección MAC se puede utilizar para realizar ataques como:

  • Este mecanismo de cambio de dirección MAC permite invalidar o saturar mecanismos de tracking o identificación de dispositivos en base a su dirección MAC. Esto se realiza mediante la emisión de paquetes de advertising con diferentes MAC de manera continua, inyectando datos “falsos” en estos sistemas y mejorando la privacidad.
  • Al suplantar la MAC de un dispositivo e iniciar un proceso de advertising desemboca en que dispositivos que conozcan esa dirección MAC inicien una conexión con nosotros. Esto permite establecer conexiones con dispositivos que pueden no estar anunciándose o que incluso se encuentren en un estado “no conectable”. Este es el comportamiento seguido por muchos dispositivos que no se anuncian de manera continua como hacen la gran mayoría de los teléfonos móviles. Estos permanecen a la escucha esperando paquetes de anuncio de dispositivos periféricos como auriculares a los que conectarse cuando se encienden.
  • Contar con la capacidad de suplantar una MAC ya conocida para otro dispositivo habilita la realización de pruebas de reemparejamiento. Un ejemplo de esto es la posibilidad de suplantar la MAC de un teléfono móvil y tratar de iniciar una conexión con auriculares que se encuentren en modo “no emparejable”. Puesto que la MAC ya es conocida, se permite la conexión, pero si se envía un mensaje indicando que la clave de cifrado anterior ya no es válida, si el dispositivo lo soporta se puede renegociar la clave a pesar de no encontrarse los auriculares en un modo “emparejable”.

    Esto es posible ya que en el estándar de Bluetooth se contempla la opción de renegociar claves para algunos modos de seguridad, estableciendo una nueva clave e invalidando la ya existente. En dispositivos en los que no existe hardware como botones para verificar esta renovación de claves, en ocasiones se realiza de forma automática sin confirmación de usuario.

  • La capacidad de suplantar MACs permite la denegación de servicio en algunos dispositivos. Un ejemplo es suplantar la dirección MAC, conectarse a un dispositivo y mantener la conexión abierta de manera indefinida de manera que el usuario no pueda conectarse a ese dispositivo. Esta denegación de servicio puede llegar a ser semi-permanente si además de establecer una conexión el dispositivo permite realizar un proceso de renegociación de claves, estableciendo una nueva e invalidando la clave original. Esto obliga al usuario a realizar el proceso de emparejamiento en el momento de usar el dispositivo.
  • Con la capacidad de forzar al usuario a realizar múltiples procesos de emparejamiento se fuerza la realización de procesos sensibles a ataques de fuerza bruta y que permiten la construcción de problemas criptográficos. Más particularmente, el proceso de emparejamiento es de especial importancia porque requiere de la interacción de usuarios para la validación de números de baja complejidad. Esto hace que este proceso sea susceptible a ataques de fuerza bruta o problemas criptográficos que permiten recuperar claves de conexión legítimas.

Read Memory command

CommandOCFCommand parametersReturn parameters
HCI_ESP32_CMD_READ_MEM0x01Start_Address
Access_Size
Length
Status
Length
Data

Description:

Este comando permite la lectura de memoria del controlador Bluetooth. Los parámetros del comando indican la dirección en la que comienza la lectura de datos, el tamaño de las unidades a leer (8, 16 o 32 bits) y el número de unidades a leer.

Los valores posibles del parámetro Access_Size están limitados a los enteros 8, 16 o 32.

Command Parameters:

Start_Address – Size: 4 Octets

ValueParameter description
0xXXXXXXXXMemory address from where to start reading

Access_Size – Size: 1 Octet

ValueParameter description
0xXXValor del tamaño del acceso, los valores posibles son: 8, 16, 32

Length: – Size: 1 Octet

ValueParameter description
0xXXNumber of elements of Access_Size to be read

Return parameters:

Status – Size: 1 Octet

ValueParameter description
0x00HCI_Esp32_Read_Memory command succeeded.
0x01 to 0xFFHCI_Esp32_Read_Memory command failed. See [Vol 1]
Part F, Controller Error Codes, for error codes and descriptions

Length – Size: 1 Octet

ValueParameter description
0xXXNumber of elements returned

Data – Length x Access_Size Octets

ValueParameter description
0xXXRead data

Desde el punto de vista de la seguridad, este comando es muy interesante para obtener cualquier valor de memoria del dispositivo con los siguientes casos de uso:

  • Exfiltración de secretos de la memoria del ESP32. Esto incluye secretos o claves usadas durante la operación habitual del chip como pueden ser claves de redes WiFi en caso de que el chip también opere como tarjeta WiFi, claves de cifrado de otros servicios y también permite extraer claves de emparejamiento del controller de Bluetooth presentes en el dispositivo y aquellas a las que el host no tenga acceso por motivos de privilegios y permisos.

    Teniendo acceso sin privilegios a un dispositivo no es posible recuperar las claves de emparejamiento porque estas se almacenan en un lugar seguro. Con la capacidad de enviar paquetes HCI al controller Bluetooth y enviando un comando de conexión a un dispositivo concreto, se logra que el controller inicie la conexión, solicitando al kernel del host la clave de emparejamiento para ser usada desde el controller. Durante este proceso se extrae la clave del controller mediante la lectura de la memoria.

  • Mecanismo de depuración. Permite identificar regiones de memoria libres, así como ser usado mecanismo de depuración.

Write Memory command

CommandOCFCommand parametersReturn parameters
HCI_ESP32_CMD_WRITE_MEM0x02Start_Address
Access_Size
Length
Data
Status

Description:

Este comando permite la escritura de datos en direcciones de memoria arbitrarias del ESP32. El parámetro Start_Address indica la dirección donde se inicia la escritura. El parámetro Access_Size indica el tamaño en bits de cada unidad a escribir y toma el valor 8, 16 o 32. El parámetro Length indica el número total de unidades a escribir y Data es un buffer con el contenido de datos a escribir, siendo su longitud Access_Size x Length.

Command Parameters:

Start_Address – Size: 4 Octets

ValueParameter description
0xXXXXXXXXDirección de memoria desde la que leer

Access_Size – Size: 1 Octet

ValueParameter description
0xXXValor del tamaño del acceso, los valores posibles son: 8, 16, 32

Length – Size: 1 Octet

ValueParameter description
0xXXLength of the Data field

Data – Length x Access_Size Octets

ValueParameter description
0xXXRead Data

Return parameters:

Status – Size: 1 Octet

ValueParameter description
0x00HCI_Esp32_Read_Memory command succeeded.
0x01 to 0xFFHCI_Esp32_Write_Memory command failed. See [Vol 1]
Part F, Controller Error Codes, for error codes and descriptions

Desde el punto de vista de la seguridad, este comando es el que tiene mayor interés entre los mencionados.

Se han identificado los siguientes puntos relevantes desde el punto de vista de la seguridad haciendo uso de este comando HCI local:

  • Ejecución de código en el ESP32. La manera más sencilla es sobrescribir parte de una función, por ejemplo, el callback “r_hci_cmd_received” del firmware, ejecutado durante el proceso de recepción de comandos HCI en el ESP32. Una vez sobrescrito el callback, al enviar el comando HCI se ejecuta el código inyectado en la memoria del ESP32 tomando el control de este.
  • Bypass del “Secure Boot”, la protección contra la ejecución de código no firmado de Espressif. Dado que la escritura se realiza directamente sobre la memoria RAM del ESP32, y la escritura ocurre después de haber pasado las validaciones de los mecanismos de protección del firmware, estos controles no tienen efecto sobre las modificaciones realizadas una vez el firmware es cargado en la memoria RAM.
  • Lectura de memoria flash cifrada. Con la capacidad de ejecución de código en el dispositivo, se pueden realizar lecturas de la memoria flash mediante las llamadas a las funciones internas del API de memoria flash esp_flash_read() para leer los contenidos de la flash en formato cifrado o esp_flash_read_encrypted() para leer los contenidos ya descifrados. Estas funciones en combinación con la capacidad de generar eventos HCI mediante código, permiten volcar el contenido completo del firmware descifrado, logrando un bypass de los mecanismos de cifrado de la memoria flash de Espressif y permitiendo la ingeniería inversa de los contenidos del firmware.
  • Bypass de autenticación mediante inyección de claves. Mediante la primitiva de escritura en el ESP32 se modifica la función “r_llc_ltk_req_send” del firmware, sustituyéndola por una que verifique en la conexión entrante la dirección MAC de la que proviene la conexión. Esto permite que para una MAC concreta, en lugar de generar el evento que consulta al host por una clave de emparejamiento, esta misma función genera los eventos correspondientes al comando HCI LE Long Term Key Request Reply mediante una sola llamada a la función “r_hci_le_ltk_req_reply_cmd_handler”. De esta manera, el ESP32, ante una conexión entrante de una MAC determinada, utiliza una clave de cifrado prefijada que permite la conexión cifrada de un dispositivo sin alertar al host. De esta manera, podremos conectarnos al dispositivo modificado en cualquier momento de manera autenticada y cifrada sin necesidad de emparejamiento o interacción por parte del usuario.
  • Instalación de una puerta trasera. La recepción de los paquetes Bluetooth LE se realiza en la función “llc_llcp_recv_handler” del firmware. Esta función verifica si los paquetes que han llegado del módulo RF son válidos y realiza las llamadas a las funciones correspondientes para su procesamiento. La modificación de esta función habilita el procesamiento en funciones programadas por nosotros de paquetes no estándar que en su versión original serían descartados como inválidos.

    Esto permite el envío y la ejecución de código de manera remota en el ESP32 sin autenticación, lo que brinda el control absoluto del chip sin necesidad de tener un acceso físico mientras no se reinicie el dispositivo. A partir de este momento se pueden enviar remotamente nuevas instrucciones al chip para la captura o retransmisión de nuevas claves Bluetooth, WiFi u otros secretos intercambiados en la comunicación.

  • Instalación de puerta trasera persistente. Mediante la ejecución de código mencionada en los puntos anteriores llamando a las funciones internas de escritura de la memoria flash (esp_flash_write()) para almacenar código en el firmware se consigue permanencia ante reinicios del dispositivo.

    La vía más sencilla para esto es la modificación de cualquier función que se ejecute durante el arranque del dispositivo, como por ejemplo “app_main”.

    Este caso permitiría consolidar el control del chip sin necesidad de acceso físico, permitiendo la exfiltración de información de manera permanente o permitiendo el despliegue de nuevas modificaciones para implementar ataques que permitan la extracción de información de otros dispositivos.

    Esta persistencia es posible cuando el ESP32 no implementa SecureBoot o utiliza la versión 1. En el caso de la versión 2 de SecureBoot, debido a las mejoras implementas por Espressif, es necesaria una clave criptográfica privada del desarrollador del firmware que no está presente en la memoria del chip.

En conclusión

Los comandos HCI propietarios encontrados en el ESP32 ofrecen un gran potencial no solo para la implementación de ataques Bluetooth sino desde el punto de vista de la ciberseguridad del propio chip.

Desde la versatilidad de realizar ataques de suplantación de identidad mediante el comando de modificación de la MAC del dispositivo hasta la implementación de ataques avanzados mediante la modificación del comportamiento del controlador.

También es posible, mediante el comando de escritura en memoria, la evasión de los mecanismos de protección contra ejecución de código no firmado y de los mecanismos de cifrado de flash para evitar la extracción de secretos del chip.

Este mismo comando podría permitir la instalación de puertas traseras mediante la inserción de claves en el dispositivo para permitir la conexión de dispositivos específicos o la modificación del código para permitir la ejecución de código remoto mediante comandos vía aire.

Espressif ha informado en su blog que las funciones reportadas por Tarlogic Security no suponen un problema de seguridad explotable remotamente o a través de comandos y señales Bluetooth inalámbricas. También ha notificado su interés en deshabilitar estos comandos de depuración no documentados en nuevos dispositivos de producción con el objetivo de mejorar la seguridad del chip.

Update

10/03/25: Ver artículo



🚀 ¡Lidera el Mundo Digital con el Mejor Hosting de Argentina! 🚀

En Full Tech Solutions, ofrecemos Cloud Hosting de alto rendimiento, ideal para emprendedores, negocios y desarrolladores que buscan velocidad, seguridad y soporte experto.

Velocidad Ultra Rápida: Tu sitio web cargará en un abrir y cerrar de ojos.
🔒 Máxima Seguridad: Protección avanzada para tus datos y tranquilidad para tu negocio.
📞 Soporte 24/7: Nuestro equipo de expertos siempre listo para ayudarte.

No solo elijas un hosting. Elige el mejor con Full Tech Solutions y marca la diferencia.

🌐 ¡Impulsa tu presencia online con el hosting más confiable de Argentina!

ESCRIBIR UN COMENTARIO

¿Qué está pensando?

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *