Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CMF-Watch-Pro-2-BLE-Protocol — Protocolo BLE de ingeniería inversa para el CMF Watch Pro 2, documentando el diseño GATT, tramas de comandos cifradas con AES-128-CBC, handshake de autenticación y sincronización de datos de salud para el desarrollo de aplicaciones complementarias alternativas. | Kitploit
Herramientas/GitHubGitHub/joshuapassos/cmf-watch-pro-2-ble-protocol
Seguridad de Sistemas EmbebidosSeguridad BluetoothSeguridad IoTIngeniería InversaSeguridad InalámbricaCriptografíaSeguridad MóvilSeguridad de Hardware e IoTAnálisis de Firmware

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
GitHubjoshuapassos/cmf-watch-pro-2-ble-protocol

CMF-Watch-Pro-2-BLE-Protocol

Protocolo BLE de ingeniería inversa para el CMF Watch Pro 2, documentando el diseño GATT, tramas de comandos cifradas con AES-128-CBC, handshake de autenticación y sincronización de datos de salud para el desarrollo de aplicaciones complementarias alternativas.

Ver RepositorioSitio web
342hace 2 mesesAún no revisado

CMF Watch Pro 2 — Protocolo BLE (ingeniería inversa)

No oficial. Este documento describe el protocolo Bluetooth Low Energy (BLE) del CMF Watch Pro 2 (CMF by Nothing), reconstruido mediante ingeniería inversa para una aplicación complementaria alternativa. No está afiliado ni respaldado por Nothing/CMF. Úselo bajo su propio riesgo.

Todos los enteros de múltiples bytes en el encabezado de trama y los opcodes son big-endian. Los enteros dentro de las cargas útiles de comandos son little-endian salvo que se indique lo contrario (esto refleja el firmware del dispositivo) — cuidado con las excepciones (GOALS_SET, GPS_PUSH, el desplazamiento/longitud de la transferencia masiva son big-endian).

Marcadores de confianza

Cada afirmación no obvia a continuación está etiquetada con cómo se estableció:

  • ✅ validado en el dispositivo — observado en una captura en vivo descifrada o probado contra un reloj real.
  • 🔎 de firmware / RE del APK — extraído descompilando el firmware (1.0.0.73) o el APK oficial (3.5.7); consistente con el código pero no probado en tiempo de ejecución.
  • 🟡 parcialmente probado — establecido estructuralmente (sin conexión, en todo el corpus o mediante RE) pero el paso restante necesita el reloj y no se ha ejecutado.
  • ⚠️ [incierto] — inferido, no confirmado; puede ser incorrecto.

Cuando una sección posterior corrige una anterior, el texto anterior se conserva con una referencia en lugar de eliminarse — saber qué lecturas se probaron y se refutaron le ahorra a la siguiente persona el mismo desvío.

Dispositivo de prueba para todas las capturas: CMF Watch Pro 2-5485, fw 1.0.0.73, serie CI04102520008192, MCU Actions ATS3089C (Cortex-M4), pantalla 466×360.


1. Disposición GATT

El teléfono es el cliente GATT; el reloj es el periférico, que se anuncia como CMF Watch Pro 2-XXXX (4 caracteres hexadecimales).

PropósitoServicioCaracterísticaPropiedades
Escritura de comandos0000fff0-0000-1000-8000-00805f9b34fb0000fff2-…Write
Notificación de comandos0000fff0-…0000fff1-…Notify
Escritura de shell (AT)—77d4ff01-2fe2-2334-0d35-9ccd078f529cWrite
Notificación de shell (AT)—77d4ff02-…Notify
Escritura de datos masivos—02f00000-0000-0000-0000-00000000ffe1Write
Notificación de datos masivos—02f00000-…ffe2Notify

Habilite las notificaciones escribiendo 01 00 en cada CCCD (00002902-…). El canal de comandos (fff1/fff2) transporta el protocolo enmarcado a continuación. El canal de shell (77d4…) transporta texto plano estilo AT (p. ej., AT GETSECRET; consulte §14). El canal de datos (02f0…) transporta blobs binarios grandes (esfera de reloj, firmware, AGPS), coordinados por opcodes de control en el canal de comandos.

UUID de servicios — el reloj anuncia ~10 servicios primarios. Enumerados en una unidad real: 0xfff0 (comandos), 0x180f (batería), 0x180a (información del dispositivo), 0xefe7, 0xffd0, 02f00000-…ffe0 y 02f00000-…fe00 (datos), 77d4e67c-2fe2-2334-0d35-9ccd078f529c (shell / emparejamiento), e49a3001-f69a-11e8-8eb2-f2801f1b9fd1, f48a23c0-f69a-11e8-8eb2-f2801f1b9fd1.

⚠️ El servicio de shell tiene el UUID 77d4e67c-…, no 77d4ff00-…. Revisiones anteriores de este documento asumían que el servicio compartía el prefijo ff00 de sus características (77d4ff01/77d4ff02, §14) — no es así, al menos en la unidad en la que se verificó (hallazgo de freethinkel/fmc, consulte §Fuentes). Los UUID de las características no han cambiado. No se ha verificado si 77d4e67c es estable entre unidades — enumere en lugar de codificar.

🌐 Nota sobre Web Bluetooth. Chromium solo descubre servicios que la página haya listado en optionalServices, incluso para una llamada sin filtro a getPrimaryServices() — una página que liste 3 servicios verá 3, mientras que chrome://bluetooth-internals (la propia capa C++ de Chrome, sin ámbito) muestra los 10. Si escribe un cliente de navegador, liste todos los UUID anteriores de antemano o el emparejamiento fallará con servicios que existen claramente. No hay Web Bluetooth en Firefox/Safari; requiere un gesto del usuario + HTTPS/localhost.

✅ Una sesión real completa se ejecutó en el único canal de comandos — durante una captura de 160 s de uso intensivo no hubo tráfico en los canales de datos/firmware o shell excepto durante una transferencia explícita de OTA/esfera de reloj.


2. Formato de trama (0xF5)

Cada mensaje del canal de comandos está envuelto en una o más tramas con encabezado de 11 bytes:``` +------+-----------+--------+-------------+-------------+--------+-------------------+ | 0xF5 | chunkLen | cmd1 | chunkCount | chunkIndex | cmd2 | chunk bytes … | | 1 B | 2 B (BE) | 2 B BE | 2 B BE | 2 B BE | 2 B BE | chunkLen bytes | +------+-----------+--------+-------------+-------------+--------+-------------------+ __________________________ 11-byte header ____________________________/

- `cmd1`/`cmd2` juntos forman el **opcode** (ver §6). 🔎 confirmado contra el constructor de tramas
  de la app oficial (`C6117b.m30831g`).
- `chunkCount` = total de fragmentos para este comando; `chunkIndex` tiene base **1**.
- `chunkLen` = número de bytes de `chunk` en esta trama.
- Una sola escritura BLE puede fragmentarse según el MTU del enlace; el receptor almacena los bytes
  crudos y vuelve a extraer tramas completas. Las cargas útiles grandes se dividen en varios
  fragmentos (mismo `cmd1/cmd2`, `chunkIndex` creciente) y se reensamblan en orden.

### Convención de opcodes (✅ confirmado en el cable)

- `cmd1 = 0xFFFF`: `cmd2` en `0x80xx`/`0x90xx` = teléfono→reloj (solicitud/ajuste); `0x00xx`/`0xa0xx` =
  reloj→teléfono (respuesta). Los pares coinciden por el byte bajo (`0x9055`↔`0xa055`, `0x8051`↔`0x0051`).
- `cmd1` específico de función: el sufijo de `cmd2` = `0x0001` **SET**, `0x0002` **GET**, `0x0003` **ACK**.

### Cuerpo del fragmento

Para cada fragmento, el cuerpo es `payloadPiece ‖ CRC32_LE(payloadPiece)` (CRC de 4 bytes, little-endian,
zlib/IEEE). Si el comando está **cifrado** (ver §3), todo `payloadPiece ‖ CRC` se cifra luego con
AES-128-CBC/PKCS7 y ese texto cifrado se convierte en el `chunk` de la trama.

**Particularidad del texto plano:** para opcodes en texto plano, el reloj *cuenta* el CRC de 4 bytes en
`chunkLen` pero **no** lo transmite. Así que al decodificar una trama en texto plano, la longitud real
de los datos es `chunkLen − 4`. (Las tramas cifradas llevan el CRC dentro del texto cifrado como es normal).

Tamaño de fragmento (para que los fragmentos cifrados caigan en los límites de bloque AES), con
`maxWrite = mtu − 3`:
- cifrado: `floor((maxWrite − 11) / 16) * 16 − 4 − 1`
- texto plano: `maxWrite − 11 − 4 − 1`

✅ Todos los valores de `chunkLen` observados en tramas cifradas fueron múltiplos de 16 (el alineamiento
de bloques se cumple).

---

## 3. Primitivas criptográficas

- **AES-128-CBC** con relleno **PKCS7** y un **IV fijo** (del firmware
  `CmfCharacteristic.AES_IV`):
  `50 51 52 53 54 55 56 57 60 61 62 63 64 65 66 5A`.
- **CRC32** (zlib/IEEE), emitido como 4 bytes little-endian.
- **SHA-256** sobre la concatenación de las partes.

Derivación de claves:```
authkey      = SHA256( rnd1 ‖ rnd2 ‖ secret )[0..16]      // persisted across sessions
sessionKey   = SHA256( nonce ‖ authkey )[0..16]           // per connection
  • secret = secreto del dispositivo de 16 bytes (obtenible desde el reloj mediante el comando de shell AT GETSECRET → GETSECRET:<32-hex>,OK).
  • rnd1 = 16 bytes aleatorios elegidos por el teléfono; rnd2 = 16 bytes aleatorios del reloj.
  • nonce = bytes de la respuesta de nonce del reloj.
Descargar herramienta