
Proof-of-concept exploitant l'injection de commandes DUML via Bluetooth sur les drones DJI, envoyant des commandes non authentifiées pour lire les identifiants, modifier la configuration Wi-Fi et contrôler les systèmes de l'aéronef.
Les drones DJI exposent une interface Bluetooth utilisée pour établir une connexion à l'interface Wi-Fi du drone et échanger les identifiants Wi-Fi.
L'interface Bluetooth vérifie l'UUID de confiance de l'appareil pour trois commandes :
Les commandes restantes ne nécessitent pas la même vérification d'authentification. Par conséquent, un attaquant distant à portée Bluetooth peut être en mesure d'envoyer des commandes DUML non autorisées au drone.
Selon la commande, un attaquant peut être en mesure de modifier la configuration du drone, notamment en changeant le mot de passe Wi-Fi et en accédant potentiellement au réseau interne du drone, en activant ou désactivant les interfaces radio, en redémarrant ou éteignant l'aéronef, en réinitialisant la configuration et en effectuant d'autres actions.
Le POC fournit un registre de commandes qui permet de tester les commandes disponibles sans modifier le code source Python. Le registre de commandes, incluant la commande, le récepteur, les exigences d'authentification et la description de chaque commande, est défini dans commands.json.
| Produit | Version affectée |
|---|---|
| DJI Neo | 0 – 01.00.0400 |
| DJI Neo 2 | 0 – 01.00.0500 |
| DJI Flip | 0 – 01.00.1200 |
| DJI Air 3 | 0 – 01.00.1600 |
| DJI Air 3S | 0 – 01.00.1400 |
| DJI Avata 2 | 0 – 01.00.0400 |
| DJI Avata 360 | 0 – 01.00.0300 |
| DJI Mavic 3 | 0 – 01.00.1400 |
| DJI Mavic 3 Classic | 0 – 01.00.0800 |
| DJI Mavic 3 Pro | 0 – 01.01.0700 |
| DJI Mavic 4 Pro | 0 – 01.00.0500 |
| DJI Mini 2 | 0 – 01.07.0200 |
| DJI Mini 3 | 0 – 01.00.0500 |
| DJI Mini 3 Pro | 0 – 01.00.0900 |
| DJI Mini 4 Pro | 0 – 01.00.1100 |
| DJI Mini 5 Pro | 0 – 01.00.0600 |
https://github.com/user-attachments/assets/57f51df2-5160-404c-9fd3-2a3a8b700008
# Clone the repository
git clone https://github.com/Wh02m1/CVE-2026-78306-POC.git
cd CVE-2026-78306-POC
# Create and activate a Python virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
python3 ble_console.py
Les commandes suivantes sont enregistrées dans commands.json. Le POC sépare les commandes en opérations de lecture, de configuration, de contrôle radio, de réinitialisation, système et de paramètres.
Ces opérations sont classées comme danger dans le POC et nécessitent donc une confirmation explicite avant d'être envoyées.
Les commandes de contrôle radio sont implémentées via les gestionnaires dji_network correspondants.
| Commande | Ce qu'elle fait |
|---|---|
| Factory Reset WIFI | Restaure la configuration Wi-Fi à son état par défaut. |
| Factory Restore Params | Restaure la table des paramètres de configuration réseau aux valeurs d'usine. |
Le POC marque les deux opérations comme dangereuses car elles modifient la configuration persistante.
| Commande | Ce qu'elle fait |
|---|---|
| Change a parameter | Modifie un paramètre de configuration du drone à l'aide de son hash de nom 32 bits. |
| Reset a parameter | Réinitialise un paramètre de configuration à sa valeur d'usine. |
Le POC obtient les noms de paramètres depuis flyc_parameters.txt et fournit une sélection interactive des paramètres. Pour ajouter un paramètre connu que vous souhaitez modifier ou réinitialiser, ajoutez son nom à flyc_parameters.txt. Le paramètre sera alors disponible pour sélection au démarrage du POC.
commands.json, pas le codeLe menu est généré à partir de commands.json au démarrage. Pour ajouter une commande, ajoutez un nouvel objet à la liste commands d'une section. La commande apparaîtra au prochain démarrage du POC.
Exemple :
{
"label": "GET Channel",
"cmd_set": "0x07",
"cmd_id": "0x2c",
"receiver": "0x07",
"payload": "",
"tier": "read",
"bt_reply": true,
"note": "wms_evt_get_chan -> wifi_mgmt_get_chan."
}
Le récepteur par défaut est 0x07 (network:0) et l'expéditeur par défaut est 0x02 (mobile:0).
Les générateurs de charge utile interactifs sont définis dans payload_builders.py.
Les générateurs disponibles incluent :
ssidpskcountrymacchannelbss_typepower_levelrawPour ajouter un nouveau générateur, implémentez la fonction, enregistrez-la dans BUILDERS et référencez son nom depuis commands.json.
Les commandes classées comme danger nécessitent une confirmation explicite avant transmission.
L'écran de confirmation affiche des informations telles que :
──────────────────────────────────────────────────────────────────────
!!! DANGEROUS COMMAND !!!
──────────────────────────────────────────────────────────────────────
COMMAND device_reset L1 config
ROUTE 00/de -> ve_air:1
PAYLOAD 11 01 00 00 00 00
DOES system / FC / gimbal / camera / wifi / sdr config reset
WARNING The FC configuration reset can restart the motors.
──────────────────────────────────────────────────────────────────────
Type YES to send:
Les informations DOES proviennent du champ note de la commande, tandis que les avertissements supplémentaires proviennent du champ warn dans commands.json.
La fonction Change a parameter donne accès aux paramètres de configuration connus listés dans flyc_parameters.txt.
Un paramètre peut être sélectionné par nom, fourni avec une valeur, converti vers la largeur little-endian sélectionnée, puis envoyé à l'aide de set_cfg_item (0x03/0xf9).
Reset a parameter utilise reset_cfg_item (0x03/0xfa) pour restaurer le paramètre sélectionné à sa valeur d'usine.
Le POC fournit également plusieurs macros prédéfinies :
| Macro | Description |
|---|---|
| Restart Wifi | Arrête puis démarre le Wi-Fi (0x42 suivi de 0x41). |
| SET NEW PSK + Restart wifi | Modifie la PSK puis redémarre le Wi-Fi. |
| Probe read commands | Envoie les commandes de lecture enregistrées et indique quelles commandes répondent. |
Les macros sont définies séparément des entrées de commande individuelles.
⚠️ ATTENTION : Cette preuve de concept est strictement destinée à des fins éducatives, de recherche en sécurité et de tests d'intrusion autorisés.
Ce POC démontre des problèmes de sécurité dans l'interface de gestion des commandes Bluetooth/DUML de DJI. Certaines commandes peuvent modifier la configuration de l'appareil, désactiver les interfaces radio, interrompre la connectivité, redémarrer ou éteindre l'aéronef, réinitialiser la configuration ou supprimer des données stockées.
⚠️ N'utilisez PAS ce POC contre tout aéronef, appareil, réseau ou système que vous ne possédez pas ou pour lequel vous ne disposez pas d'une autorisation explicite de test.
Certaines commandes peuvent entraîner une perte de données, des modifications de configuration, une perte de connectivité, une perturbation de l'appareil ou d'autres conséquences imprévues. Les tests ne doivent être effectués que dans un environnement contrôlé où l'aéronef ainsi que les personnes et biens environnants ne sont pas exposés à un risque.
Les auteurs ne sont pas responsables des dommages, pertes de données, interruptions de service, exploitation de l'aéronef ou autres conséquences résultant de l'utilisation ou de l'usage abusif de ce POC.
⚠️ En utilisant ce POC, vous acceptez la responsabilité de vous assurer que vos tests sont autorisés et conformes à toutes les lois, réglementations et exigences de divulgation responsable applicables.
| Commande | Ce qu'elle fait |
|---|
| GET SSID | Récupère le SSID Wi-Fi configuré. |
| GET PSK | Récupère la clé pré-partagée WPA2 du Wi-Fi. |
| GET MAC | Récupère l'adresse MAC du point d'accès Wi-Fi. |
| GET Country Code | Récupère le code pays réglementaire à deux lettres. |
| GET Channel | Récupère le canal Wi-Fi actuellement actif. |
| GET Band | Récupère la sélection de bande 2,4/5 GHz configurée. |
| GET RSSI | Interroge le gestionnaire RSSI ; cette version du firmware contient une implémentation stub. |
| GET WiFi/BT status | Récupère l'état des radios Wi-Fi et Bluetooth. |
| GET Device Info/Model | Récupère les informations sur l'appareil et le modèle. |
| GET Version | Récupère la version du démon. |
| GET Bluetooth Name | Récupère le nom de l'appareil Bluetooth. |
| Commande | Ce qu'elle fait |
|---|
| SET SSID | Modifie le SSID Wi-Fi configuré. |
| SET PSK | Modifie le mot de passe Wi-Fi configuré. |
| SET MAC Address | Modifie la configuration BSSID Wi-Fi à l'exécution. |
| SET Country Code | Modifie le code pays réglementaire configuré. |
| SET Country Code Ext | Gère la configuration étendue du code pays. |
| SET Channel | Modifie le canal Wi-Fi et provoque le redémarrage du point d'accès. |
| Commande | Ce qu'elle fait |
|---|
| Start WIFI | Démarre l'interface Wi-Fi et les services associés. |
| Stop WIFI | Arrête l'interface Wi-Fi. |
| Restart WIFI + BT | Redémarre les sous-systèmes Wi-Fi et Bluetooth. |
| Start Bluetooth | Démarre le sous-système Bluetooth. |
| Stop Bluetooth | Arrête le sous-système Bluetooth et met fin à la session en cours. |
| Sysmode power control | Contrôle l'état d'alimentation Wi-Fi/Bluetooth. |
| Commande | Ce qu'elle fait |
|---|
ftpd_start | Démarre le service dji_ftpd. |
storage_export_enable | Active la configuration d'export du stockage. |
storage_export_disable | Désactive la configuration d'export du stockage. |
play_sound | Déclenche un son de l'aéronef. |
mute | Coupe le son du haut-parleur de l'aéronef. |
unmute | Réactive le son du haut-parleur de l'aéronef. |
reboot_plain | Redémarre l'aéronef. |
reboot_poweroff | Éteint l'aéronef. |
reboot_powersave | Place l'aéronef en mode économie d'énergie. |
device_reset L1 config | Réinitialise la configuration système, contrôleur de vol, nacelle, caméra, Wi-Fi et SDR. |
device_reset L2 +MEDIA | Effectue la réinitialisation L1 et formate les médias/le stockage. |
device_reset L3 +log | Effectue la réinitialisation L2 et efface en plus le journal système. |
| Champ | Requis | Signification |
|---|
label | Oui | Texte affiché dans le menu. |
cmd_set | Oui | Identifiant d'ensemble de commandes DUML. |
cmd_id | Oui | Identifiant de commande DUML. |
receiver | Oui | Octet récepteur sur le fil, (index << 5) | type. |
payload | Non | Charge utile hexadécimale. |
tier | Non | read, write ou danger. |
builder | Non | Générateur de charge utile interactif. |
auth | Non | Indique qu'un UUID de confiance est requis. |
bt_reply | Non | Contrôle si le POC attend une réponse Bluetooth. |
sender | Non | Octet expéditeur ; par défaut 0x02. |
after | Non | Action de suivi facultative. |
note | Non | Description de rétro-ingénierie affichée par le POC. |
warn | Non | Texte d'avertissement supplémentaire affiché pour les commandes dangereuses. |
| Fichier | Rôle |
|---|
ble_console.py | Point d'entrée principal, menu et exécution des commandes. |
commands.json | Registre des commandes et descriptions des commandes. |
ble_transport.py | Scan GATT Bluetooth, connexion et gestion des réponses. |
duml_protocol.py | Construction des paquets DUML v1 et gestion du CRC. |
duml_decoders.py | Décodage des réponses et gestion des codes de retour. |
payload_builders.py | Génération interactive de charges utiles. |
parameters.py | Hachage et opérations sur les paramètres de configuration. |
terminal.py | Interface terminal, invites et gestion de la sortie. |
flyc_parameters.txt | Noms des paramètres de configuration connus. |
requirements.txt | Dépendances Python. |