2 points par GN⁺ 2023-12-16 | 1 commentaires | Partager sur WhatsApp
  • En rétro-ingénierie pour intégrer à Home Assistant des guirlandes LED Bluetooth LE bon marché, le test de valeurs d’effets cachées sur une guirlande LED adressable de 10 m a rendu le contrôleur inutilisable
  • Avec Bluetooth HCI snoop sur Android et Wireshark/tshark, les paquets BLE écrits par l’app sur les lumières ont été capturés, puis les octets de contrôle ont été suivis dans les requêtes d’écriture btatt.opcode.method==0x12
  • Les paquets de l’app iDeal LED ne ressemblaient pas à de simples valeurs on/off ; après décompilation de l’APK et consultation d’une analyse existante, ils ont été déchiffrés avec une clé AES fixe présente dans libAES.so
  • Les paquets on/off déchiffrés se résumaient à un en-tête fixe et à une différence 1/0 dans le 5e octet ; les motifs d’octets ont ensuite été relevés en exécutant à répétition les fonctions couleur, luminosité et effets
  • En envoyant pour le RGB des valeurs sur 8 bits au-delà de la plage 5 bits 0x1F utilisée par l’app, des couleurs plus lumineuses étaient possibles, mais l’envoi de l’effet numéro 12 a éteint la guirlande et fait disparaître la publicité Bluetooth

Point de départ : intégrer des lumières BLE bon marché à la domotique

  • En partant du principe que les appareils communiquant en Bluetooth LE et disposant d’une app dédiée peuvent être intégrés à un système domotique, plusieurs rubans LED bon marché ont été rétro-ingéniérés
  • Auparavant, un ruban LED 5 m non adressable contrôlé en Bluetooth LE à 2,38 £ avait été connecté à Home Assistant en quelques heures, et le code correspondant a été publié dans bj_led
  • Un travail de rétro-ingénierie BLE du contrôleur LEDnetWF existe aussi dans lednetwf_ble
  • La cible cette fois était une guirlande LED adressable de 10 m posée sur le bureau, contrôlée par l’app “iDeal LED”
    • L’app propose beaucoup de fonctions et fonctionne relativement bien
    • Les LED sont probablement des WS2812 ou un produit similaire
    • Le produit est une guirlande achetée sur AliExpress

Capturer les octets BLE envoyés par l’app

  • Pour contrôler l’appareil avec son propre logiciel, il faut d’abord identifier la suite d’octets envoyée à l’appareil par Bluetooth
  • Un protocole d’éclairage typique peut être composé d’un en-tête, d’un octet de commande comme on/off ou changement de couleur, et d’un pied de paquet pouvant être une somme de contrôle
  • Sur Android, la capture se fait dans l’ordre suivant
    • Activer le mode développeur
    • Installer l’app des lumières
    • Activer Bluetooth HCI snoop dans les options développeur
    • Effectuer des actions dans l’app, comme allumer et éteindre les lumières
    • Copier le journal sur l’ordinateur avec adb pull sdcard/btsnoop_hci.log .
  • En ouvrant le journal dans Wireshark, on peut voir les octets transmis aux lumières
    • Exemple de filtre : bluetooth.dst == ff:ff:ff:ff:ff:ff && btatt.opcode.method==0x12
    • L’adresse MAC doit être remplacée par celle des lumières réelles
    • btatt.opcode.method==0x12 signifie qu’une opération d’écriture a eu lieu depuis l’appareil Android vers les lumières
  • Avec tshark, on peut extraire directement les valeurs des paquets dans le terminal
    • tshark -r <filename> -T fields -e btatt.value affiche la charge utile écrite sur le contrôleur LED

Le protocole iDeal LED ne se contentait pas d’un simple replay

  • Certaines lumières présentent, pour les actions on/off, un motif quasiment lisible tel quel
    • Par exemple, 69 96 02 01 01 et 69 96 02 01 00 se répètent
    • Le dernier octet alterne entre 1 et 0 pour indiquer l’allumage ou l’extinction
  • Cette guirlande iDeal LED répétait des suites d’octets beaucoup plus longues ; les deux types de paquets correspondant à on/off étaient distinguables, mais les valeurs ressemblaient à du bruit
  • S’il s’agit seulement d’allumer et d’éteindre, un replay consistant à retransmettre tel quel la suite d’octets capturée peut suffire
    • gatttool permet de se connecter à un appareil BLE et d’envoyer des octets
    • Le handle à utiliser doit être identifié dans Wireshark
  • Pour obtenir davantage de contrôle, il fallait comprendre la structure des paquets ; l’étape suivante a donc été l’analyse de l’app Android elle-même

Décompiler l’APK et trouver la clé AES

  • L’APK a été téléchargé puis ouvert avec jadx pour examiner le code de l’app
  • Des références à AES apparaissant dans les sources, il devenait possible que le protocole soit chiffré
  • Les hypothèses suivantes ont été posées à propos des données chiffrées
    • Le texte chiffré d’une même action ne changeant pas à chaque fois, il pouvait exister une clé cohérente
    • Comme le déchiffrement doit être rapide sur un MCU basse consommation, une clé courte est avantageuse
    • La clé pouvait ne pas être propre à chaque appareil et être fixe
  • L’app contenait une bibliothèque AES compilée nommée libAES.so, impossible à analyser avec jadx seul
  • Une analyse d’une autre personne, qui avait décompilé la bibliothèque AES avec ida free et trouvé la clé intégrée, a été trouvée ; cette clé a été testée
  • Le déchiffrement en mode AES ECB avec Crypto.Cipher a transformé les paquets on/off en une forme porteuse de sens
    • Les valeurs déchiffrées apparaissaient sous la forme 05 54 55 52 4E 01 ... et 05 54 55 52 4E 00 ...
    • Après l’en-tête fixe, le 5e octet passe à 1 ou 0 pour indiquer on/off
    • Le reste est rempli de zéros
  • À partir de cette étape, il est devenu possible de déchiffrer les paquets envoyés par l’app et de reproduire les mêmes commandes dans son propre code

Relever les motifs d’octets par fonctionnalité

  • La portée du protocole a été élargie en exécutant une par une toutes les fonctions de l’app et en enregistrant les octets transmis
  • Chaque action a été répétée plusieurs fois, et des séquences extinction/allumage ont été insérées pour délimiter les sections
    • La couleur a été changée plusieurs fois dans l’ordre red, green, blue
    • La luminosité a été modifiée selon 100 %, 50 %, 10 %, 50 %, 100 %
    • Des off/on ont été ajoutés entre chaque groupe pour faciliter le repérage des limites dans les journaux de capture
  • Cette méthode permet d’identifier quels octets changent selon l’action, puis de faire correspondre les actions enregistrées aux paquets capturés

L’effet numéro 12 qui a briqué le contrôleur

  • En étudiant le changement de couleur, il a été constaté que l’app n’envoyait pas de valeurs supérieures à 0x1F pour red, green et blue
    • 0x1F correspond à une plage sur 5 bits
    • En envoyant directement des valeurs sur 8 bits, des couleurs plus lumineuses fonctionnaient
  • Pour vérifier s’il existait des effets supplémentaires en plus des 10 effets utilisés par l’app, une boucle range(20) a envoyé les numéros d’effet dans l’ordre
    • De 1 à 10, tout s’est déroulé normalement
    • À 11, un comportement ressemblant à un mode caché est apparu
    • Au passage à 12, les lumières se sont éteintes
  • Ensuite, les lumières ne se sont plus rallumées
    • Elles n’émettaient plus de publicité Bluetooth
    • La connexion ne fonctionnait plus non plus
    • Maintenir le bouton enfoncé à la mise sous tension ne les a pas restaurées
    • Les laisser débranchées toute la nuit n’a rien changé
  • L’hypothèse d’une corruption du firmware par dépassement de tampon a été envisagée, mais la cause n’a pas été confirmée
  • Les LED elles-mêmes étant des LED adressables standard, la guirlande peut être réutilisée en la connectant à un autre microcontrôleur

Résultats restants et avertissement

  • Malgré l’échec, la majeure partie du protocole a été documentée, et un projet GitHub incluant un composant personnalisé Home Assistant a été créé
  • Le composant fonctionne, mais des expérimentations du même type peuvent endommager le contrôleur des lumières ; elles sont donc à mener à vos propres risques

1 commentaires

 
GN⁺ 2023-12-16
Commentaires de Hacker News
  • Plutôt qu’un « en-tête fixe » de FTA, cela ressemble à un octet de longueur (« la commande fait 5 octets »), avec la commande TURN, l’argument 0/1, puis un remplissage par des zéros jusqu’à 16 octets

    • 54 55 52 4E saute immédiatement aux yeux comme les lettres majuscules TURN
      Quand on sait que les chiffres commencent à 0x30, les majuscules à 0x41 et les minuscules à 0x61, il devient facile de repérer des motifs alphanumériques dans un dump hexadécimal
      Ce genre de connaissance est utile pour les chaînes courtes, mais quand on regarde des paquets ou des dumps mémoire, le format hexdump standard reste le meilleur choix
    • Bien vu. 0x54 55 52 4E correspond bien à T U R N
    • Bonne trouvaille. Je vais vérifier d’autres commandes pour voir si l’hypothèse de l’octet de longueur tient, et elle paraît plausible
    • Il y a de fortes chances que ce ne soit pas du padding, mais simplement un uint
    • Dans ce cas, on peut dire que l’en-tête est fixe du point de vue de la longueur et du point de départ
  • Cela pourrait être un problème d’alimentation. La famille WS281x peut s’allumer très fort, et quand on en regroupe beaucoup, elle consomme énormément de courant
    Avec une alimentation 12 V 3 A pour un ruban de 100 LED, on peut à peine tout allumer en blanc à luminosité maximale, et c’est très éblouissant
    Je regarderais donc d’abord du côté d’un fusible grillé. Le fait que le firmware n’utilise que 31 sur une luminosité maximale de 255 est aussi un indice

    • En voyant que la luminosité était limitée à 0x1f, j’ai aussi pensé à ça au début. Avec un peu de chance, l’alimentation a un fusible et seul celui-ci a sauté
      Même si ce n’est pas récupérable, une guirlande de LED WS281x standard peut être connectée à un Raspberry Pi, et mon contrôleur open source pour LED adressables peut aussi être utilisé :) https://github.com/mbevand/ledthemfight
      Il propose des effets intégrés et a été conçu de façon très modulaire pour le DIY, si bien qu’avec deux lignes de Python on peut créer un module d’effet LED personnalisé simple. Démo ici : https://youtu.be/qpd2rILsnM4
    • Bonne idée. Je vais sortir le multimètre
    • Ça ne ressemble pas à du WS2812. D’après le lien Ali publié, le ruban a quatre fils : 12V, rouge, vert et bleu
      Ça ressemble à un ruban RGB analogique où tout le ruban s’allume de la même couleur, pas à des LED adressables individuellement
      https://www.aliexpress.com/item/1005005485885067.html
      Toute personne qui veut bricoler des éclairages LED devrait absolument regarder WLED. Il y a beaucoup d’effets intégrés, une interface web, ça utilise des ESP32 ou ESP8266 très bon marché comme contrôleurs, et ça peut aussi réagir au son. Je fais tourner WLED sur mes guirlandes de Noël d’intérieur en ce moment, et le rendu est excellent
    • Merci pour l’astuce. J’ai mis à jour le code pour le décaler de 3 bits vers la droite et revenir à un nombre sur 5 bits
      C’est une façon élégante de limiter la consommation électrique
  • Bon article. Ça me rappelle la fois où j’ai essayé de rétroconcevoir mes éclairages et où j’ai découvert qu’ils étaient chiffrés
    L’un était un amaran 60d et les autres quelques panneaux LED sur batterie SmallRig RM75 ; je voulais pouvoir tous les allumer et les éteindre avec un seul script, sans manipuler deux applis séparées
    J’ai passé pas mal de temps à rétroconcevoir les applis et le protocole, et les deux lampes semblaient utiliser la même procédure de négociation, mais implémentée avec des bibliothèques différentes
    J’ai essayé d’imiter l’échange de clés Diffie-Hellman effectué à la connexion, mais j’ai fini par abandonner. De mémoire, il y avait ensuite une ou deux étapes supplémentaires, et après l’envoi de la première clé, il envoyait encore un nombre qui ressemblait à de l’aléatoire (une autre clé ?), sans que je parvienne à comprendre ce qu’il attendait
    En lisant cet article, je me dis que je devrais simplement essayer de mettre une clé codée en dur et voir si ça fonctionne

    • Ce serait vraiment super si quelqu’un y arrivait avec les éclairages Amaran. Cela pourrait probablement conduire à la rétroconception de toute la gamme Aputure
      Une intégration open source pour Elgato Stream Deck ou Home Assistant serait un très beau cas d’usage. Pour les YouTubeurs qui tournent des vidéos face caméra à leur bureau, ce serait bien mieux que de contrôler les lumières avec une appli mobile
  • J’ai transformé des guirlandes de Noël connectées en BLE en déchet électronique en essayant de les automatiser. Vous aussi, vous pouvez le faire

    • Je ne sais pas comment, mais j’ai vu certains de ces SmartTrash se réinitialiser complètement avec une séquence magique du genre les éteindre et les rallumer rapidement 5 fois
    • Si tu veux faire du sniffing de paquets BLE avec une approche plus centrée sur l’interface graphique, essaie l’appli nRF Connect
      Je ne sais pas pour l’iPhone, mais sur Android, en la laissant en arrière-plan, on peut capturer l’activité BLE dans une interface propre sur le téléphone. Je m’en sers tous les jours
    • Si tu contournes le contrôleur, tu peux toujours les utiliser comme des guirlandes simples/classiques
  • Ça me rappelle ces MCU de clavier qui se retrouvaient briqués lorsqu’ils recevaient certaines commandes d’éclairage
    OpenRGB a fini par devoir désactiver ce module sur le matériel concerné pour éviter qu’il ne s’exécute automatiquement. Parfois, le logiciel du constructeur déclenchait aussi le même bug
    Malheureusement, il fallait généralement envoyer un rapport USB HID pour entrer en mode de programmation in-system, mais les appareils touchés ne s’énuméraient même plus
    Reste à savoir s’il s’agissait réellement d’une corruption du firmware, ou si le matériel était endommagé à cause d’un autre comportement indéfini

  • « Envoyer du texte en clair par radio, ce n’est pas sécurisé »
    « T’inquiète, on a ajouté du chiffrement AES »

    • Tuya est vraiment comique à ce sujet. Le protocole, c’est simplement TLS au-dessus de TCP, mais chaque fois que l’appli ajoute un nouvel appareil, elle arrose toutes les STA voisines avec le mot de passe Wi-Fi
      C’est dû au mode d’appairage. L’appli diffuse des paquets à l’aveugle vers 255.255.255.255, et l’appareil cible (ampoule, prise, etc.) attend en mode promiscuous
      Le contenu des paquets est protégé par WPA2 ou équivalent, mais pas leur longueur ; l’appli envoie donc une énorme quantité de tout petits paquets dont la longueur est fixée à la valeur de l’octet ASCII du caractère suivant du handshake de configuration. Elle les envoie probablement plusieurs fois
      C’est pourquoi l’appairage prend 2 minutes, puis s’arrête toujours soudainement avant que le compteur n’atteigne 0
    • Ça ressemble à du chiffrement contre l’air ambiant
  • C’est ce qui m’avait vraiment inquiété l’an dernier quand je faisais de la rétro-ingénierie sur le contrôleur BLE de ma cheminée
    En particulier, la commande « Set password » accepte des octets bruts en entrée, alors que l’app OEM n’envoyait que des données numériques à longueur limitée
    Heureusement, il semblait tout oublier dès qu’il y avait une brève coupure d’alimentation
    Du coup, la plupart des contrôleurs BLE de la même marque semblent être restés avec le mot de passe par défaut 0000. À la moindre panne de courant, ils finissent par revenir à cet état. Si vous vous ennuyez vraiment, ça ferait un assez bon sujet de wardriving BLE
    J’ai aussi transformé mes résultats de rétro-ingénierie en intégration Home Assistant (https://github.com/kaechele/napoleon-efire), et rédigé la documentation du système et du protocole (https://bonaparte.readthedocs.io/en/latest/index.html)

  • Je cherche des guirlandes lumineuses souples et robustes à installer sur la galerie de toit d’une voiture
    Il faudrait qu’elles soient sur batterie et adaptées à l’extérieur/tous temps, et idéalement que le boîtier de batterie puisse se fixer facilement à une surface avec des colliers de serrage
    Si possible, j’aimerais un format T5 « mini », avec du RGB programmable, pour pouvoir faire rouge/vert à Noël, violet/orange à Halloween, etc. selon les saisons
    Je me demande si quelqu’un connaît un produit qui corresponde à ces critères. Les trois premiers se trouvent chez Walmart ou Home Depot, mais j’ai eu du mal à trouver quelque chose qui satisfasse le dernier
    Les recherches ne renvoient qu’un tas de bruit
    [1] https://cdn.christmaslightsetc.com/images/CategoryDetail/788...

    • Ça dépend sans doute du niveau de DIY que tu es prêt à faire
      Par exemple, on trouve facilement des rubans LED 12 V étanches IP67 (dans un tube en silicone) [0], et comme ils ont beaucoup plus de LED que des guirlandes de type éclairage de Noël, l’effet sera aussi plus marqué
      En revanche, il faudra acheter et programmer un microcontrôleur du genre Arduino, ESP32 ou ESP8266, et trouver toi-même comment tirer l’alimentation depuis la batterie de la voiture [1]
      Tu pourrais aussi mettre l’électronique dans la voiture et ne faire sortir que les fils par le coffre, en comptant sur le joint existant du coffre pour l’étanchéité
      [0] https://www.aliexpress.com/item/1005004289391906.html
      [1] https://www.aliexpress.com/item/1005005977505151.html
    • Tu peux aussi regarder les WS2811 de style « bullet string ». Si tu comptes les brancher sur le 12 V de la voiture, ils sont natifs 12 V, généralement vendus en version étanche avec des pigtails xConnect, faciles à fixer et souples
      Il est aussi facile de les ressouder avec des rallonges ou de les chaîner
      https://www.aliexpress.com/item/4000105913323.html
      D’après ce que j’ai lu, ce type de produit, ou des éclairages 5 V similaires, semble être quasiment standard pour les spectacles de lumières de Noël en extérieur
    • Rejoins le Discord WLED et regarde les salons #projects et #showcase. Il y a beaucoup de projets d’installation d’éclairage LED RGB sur des véhicules
      Attention toutefois, on peut facilement se laisser aspirer par ce domaine
      Lien d’invitation : https://discord.gg/eVhhh2Wh
  • Est-ce qu’on pourrait voir les guirlandes de Noël en panne démontées ?
    Savoir quelle puce il y a à l’intérieur pourrait donner des indices sur la présence éventuelle de mémoire flash et sur la facilité à la dumper