Analyse d'un décodeur TNT

Rédigé par Paul Viel - 08/04/2025 - dans Hardware , Reverse-engineering - Téléchargement

De nombreuses personnes possèdent un décodeur TNT, ce qui constitue une surface d'attaque importante souvent insoupçonnée. Certains modèles nécessitant une connexion internet, ils constituent un point d'accès potentiel vers le réseau local. Dans cet article, nous examinerons les protocoles utilisés par la TNT et les vulnérabilités liées à leurs implémentations.

Vous souhaitez améliorer vos compétences ? Découvrez nos sessions de formation ! En savoir plus

Introduction

En nettoyant le garage, nous avons retrouvé un décodeur TNT et avons pensé qu'il constituerait une cible idéale pour une recherche de vulnérabilités. Bien qu'il s'agisse d'un appareil couramment utilisé, nous n'avons trouvé que peu de recherches précédentes sur ce sujet.

Front of DVB receiver

Ce modèle est vendu par la société française Metronic et est toujours disponible sur leur site web. Il dispose d'un port Ethernet pour la connectivité Internet et est indispensable pour certaines fonctionnalités telles que les mises à jour météo, la radio web, etc.

L'objectif de cette recherche est d'obtenir une exécution de code sur l'appareil via des ondes radio, ce qui permettrait à un attaquant d'accéder au réseau local auquel l'appareil est connecté.

Cependant, lors de notre session de nettoyage, nous n'avons pas pu retrouver la télécommande de l'appareil. Celui-ci est presque inutilisable sans elle car la première étape lors d'un changement d'antenne sur un tel appareil est la synchronisation des chaînes, ce qui nécessite la télécommande. Les trois boutons sur la face avant sont l'alimentation, l'incrémentation et la décrémentation des chaînes, mais ils ne suffisent pas à accéder aux paramètres de l'appareil.

La documentation utilisateur spécifie qu'il peut ou non fonctionner avec une télécommande universelle. Nous avons donc essayé une méthode de force brute avec la plus grande base de données de télécommandes infrarouges que nous avons pu trouver sur Internet, mais sans succès.

Nous avons donc entamé notre analyse en recherchant le code implémentant la réception des données infrarouges.

Récupération du firmware

La première étape consiste à récupérer le firmware du produit. Comme le fabricant ne propose pas de mises à jour, il nous faudra l'extraire directement depuis l'appareil.

PCB view

Nous avons identifié deux ports sur le PCB étiquetés CN2 et J11, qui semblent être des ports de débogage. Cependant, ces derniers semblent inactifs, car aucune activité n’a été observée en y connectant un analyseur logique.

Le SoC sous le dissipateur thermique est un ALI M3626. Très peu d’informations sont disponibles en ligne concernant cette puce, et son architecture reste inconnue. Cependant, un détail notable sur cette carte est la présence d’une mémoire flash SPI, qui pourrait contenir le firmware de l’appareil.

Les données extraites de la mémoire flash comprennent quelques chaînes de caractères, mais la majorité de ces données présentent une haute entropie.
En examinant le début du dump, il semble contenir un en-tête.

First part of dump

En analysant les chaînes et les données associées, nous pouvons déduire qu’une structure de données est utilisée.
Nous avons pu déterminer certains champs de cette structure, ce qui nous a permis d’extraire des partitions du dump.

ali_file_hdr = Struct(
  "id" / Bytes(4),
  "unk" / Int32ub,
  "size" / Int32ub,
  "crc" / Bytes(4),
  "name" / Bytes(0x10),
  "version" / Bytes(0x10),
  "date" / Bytes(0x10)
)

Voici le nom des différentes partitions récupérées:

  • bootloader
  • defaultdb
  • HDCPKey
  • MAC_ADDR
  • maincode
  • netdata
  • osd_string
  • Radioback
  • seecode
  • userdb

La partition maincode semble intéressante, mais son contenu est chiffré, compressé, ou les deux, comme l’indique sa haute entropie. Une phase de rétro-ingénierie du bootloader nous a permis de localiser l'endroit où cette partition est manipulée et avons découvert qu'elle est simplement compressée à l'aide de l'algorithme LZMA.

Cependant, sans la documentation du SoC, nous n'avons pas pu comprendre complètement le code responsable de l'initialisation du matériel. En particulier, nous ne savions pas l'adresse de base où le code principal est exécuté.

Pour trouver cette adresse, nous avons commencé par une phrase de rétro-ingénierie à la recherche d'une fonction qui formate des données, comme printf, sprintf, etc. Une fois identifiée, nous avons cherché des appels à cette fonction contenant au moins deux adresses codées en dur. Les adresses codées en dur sont généralement des chaînes de caractères, ce qui signifie que la première contient %s.

Nous avons ensuite listé toutes les chaînes présentes dans le code et les avons filtrées pour trouver des paires de chaînes avec le bon offset relatif et dont la première contient %s.
Cette approche nous a donné une vingtaine de résultats potentiels mais un seul était aligné sur 512 octets. L'utilisation de cette adresse de base a parfaitement fonctionné, car toutes les références de chaînes avaient désormais un sens.

Erreurs d'IR

Avec le firmware à la correcte adresse de base, nous pouvons commencer la rétro-ingénierie pour trouver où les codes infrarouges sont traités.

L'OS du SoC est basé sur un système d'exploitation temps réel (RTOS). Les chaînes présentes dans le code suggèrent qu'il suit la spécification du noyau ITRON, bien qu'il ne semble pas utiliser l'implémentation open-source TKernel.
En recherchant certaines chaînes, nous avons trouvé un dépôt Github contenant du code source très similaire au firmware que nous possédons. Il semble concerner le ALI M3711, qui n'est pas exactement notre SoC, mais cela nous a été très utile pour comprendre certaines parties du code liées au matériel.

Du point de vue d'un attaquant, le firmware est particulièrement intéressant car il n'y a pas de traduction d'adresses, ce qui signifie que les adresses virtuelles sont identiques aux adresses physiques. Cela nous permet d'utiliser des gadgets de n'importe quel thread, à condition que nous ayons une vulnérabilité permettant de construire une ROPchain.

L'un des premiers threads lancés lors du démarrage gère l'initialisation du matériel. La fonction irc_m6303irc_init initialise le récepteur infrarouge du SoC et enregistre une callback pour une interruption spécifique.

À chaque fois que la LED infrarouge reçoit une impulsion, la fonction irc_m6303irc_lsr traite l'interruption et appelle generate_code, en lui passant le nombre de ticks écoulés depuis le démarrage en paramètre.

La majorité des protocoles infrarouge utilisent l'encodage par distance d'impulsion pour encoder l'information. Voici un exemple avec le protocole NEC :

NEC encoding

Le gestionnaire de l'interruption doit alors enregistrer l'heure de la dernière impulsion reçue et calculer la différence avec l'impulsion actuelle pour pouvoir décoder les bits transmis.

Le nom de la fonction laisse penser que le protocole NEC est utilisé, mais nous verrons qu'il n'est pas implémenté correctement. Ce protocole est relativement simple, puisqu'il utilise une adresse de périphérique et une commande, chacune encodée sur 8 bits. Voici un exemple complet de transmission NEC :

NEC transmission

Dans l'implémentation du protocole NEC de ce produit, les 32 bits reçus sont regroupés dans un entier qui est ensuite transmis à l'utilisateur.

La variable code stocke l'adresse dans l'octet de poids fort (MSB) puis son inverse logique, puis la commande et son inverse dans l'octet de poids faible (LSB).
Plus tard dans le programme, cette valeur est convertie en une autre structure.

Les MSB et LSB de la variable code ont extraits, le premier correspond à l'adresse mais le second ne correspond pas à la commande. Au lieu de cela, il correspond à son inverse logique, ce qui est une première erreur d'implémentation.

De plus, comme visible dans la description du protocole NEC ci-dessus, l'adresse et la commande sont envoyées en little-endian (bit de poids faible en premier). Or, la variable code stocke les octets reçus en big-endian et l'endianness n'est jamais changée, il s'agit de la deuxième erreur d'implémentation.

La valeur de ir_code correspondant à la touche "menu" est 0x10B7. Pour entrer dans le menu en utilisant le Flipper Zero (qui implémente correctement NEC), nous devons envoyer l'adresse 0x08 (changement d'endianness de 0x10) et la commande 0x12 (changement d'endianness et inverse logique de 0xB7).

Après avoir effectué toutes ces étapes, nous avons enfin pu utiliser l'appareil et procéder à la synchronisation des chaînes.

DVB internals

La norme DVB (Digital Video Broadcasting) est un ensemble de spécifications destinées à la transmission de télévision numérique, principalement en Europe. Dans les premières versions de ces normes, aucune mesure d'authentification n'avait été prévue. Aujourd'hui encore, en France, la plupart des chaînes n'implémentent pas cette sécurité.

Cela implique que, grâce à un signal plus puissant que l'original, il est possible de prendre le contrôle d'une chaîne et de contrôler le flux qui est décodé et affiché sur le décodeur. Cette manipulation peut être aisément réalisée à l'aide d'un HackRF.

TV flux hacked

Après démodulation, les données forment un flux de transport MPEG, qui est un flux incluant plusieurs flux élémentaires, tels que la vidéo, l'audio et les métadonnées.
Les métadonnées comprennent plusieurs tables, parmi lesquelles :

  • PAT (Program Association Table) liste tous les programmes contenus dans le flux
  • PMT (Program map specific data) contient des informations a propos des différents programmes
  • CAT (Conditional access specific data) fournit un contrôle d'accès conditionnel, c'est ce qui est utilisé par les chaînes payantes
  • EIT (Event Information Table) contient le planning des programmes 
  • etc.

Le décodeur analyse en permanence toutes ces tables. La complexité de ces normes induis une large surface d'attaque qui est susceptible de contenir des bugs.

Vulnerabilités trouvées

Lors de notre étude, nous avons identifié plusieurs vulnérabilités dans l'implémentation DVB du produit. Toutefois, aucune d'entre elles ne semble pouvoir être exploitée.

Le BAT signal

Lors de la phase de synchronisation des chaînes, le décodeur recherche la Bouquet Association Table (BAT) dans le flux MPEG. Cette table permet de relier plusieurs flux entre eux et est surtout utilisée par les chaînes payantes pour offrir l'accès à plusieurs chaînes avec un seul abonnement.

La fonction bat_event est appelée chaque fois qu'une table BAT est reçue. Elle vérifie si l'ID du bouquet est connu et le stocke si ce n'est pas le cas. Ensuite, la table est parsée et la fonction bat_on_bouqname_desc est appelée si la table contient une entrée spécifiant le nom de bouquet. Dans ces deux fonctions, l'attaquant peut contrôler le contenu de la variable data.

La valeur de bouq_cnt n'est jamais vérifiée et bouq_id possède une taille fixe de 16, ce qui pourrait conduire à un dépassement de tampon. Toutefois, la longueur maximale de l'opération memcpy est de 32, et la structure est suivie d'un large tampon inutilisé. Bien que nous ayons pu déclencher ce dépassement, nous n'avons pas réussi à provoquer un dépassement suffisamment important pour en faire une vulnérabilité exploitable.

Un bug béNIT

Egalement lors de la phase de synchronisation des chaînes, le décodeur recherche la Network Information Table (NIT). Cette table sert à associer les flux vidéo et audio. Elle peut contenir plusieurs entrées de type extension, et la fonction t2_delivery_system_descriptor_parser est exécutée pour chaque entrée. Elle vérifie si une entrée correspondant aux paramètres fournis existe déjà, et l'ajoute si ce n'est pas le cas.

La valeur de t2_info_num n'est jamais vérifiée et t2_info possède une taille fixe, ce qui peut entraîner un dépassement de tampon. Toutefois, la structure affectée se trouve dans la section .data, et aucune donnée importante n'est placée juste après.

D'autres vulnérabilités ont été découvertes lors de l'analyse de diverses autres tables, suivant un schéma similaire. Néanmoins, ces vulnérabilités ne sont pas exploitables, car les tailles sont souvent encodées sur un seul octet, ce qui empêche les vulnérabilités liées aux manipulations d'entiers. De plus, lorsque le dépassement est possible, il n'est pas suffisant pour accéder à des données sensibles.

Conclusion

En résumé, notre étude des vulnérabilités sur le récepteur DVB a mis en évidence plusieurs failles potentielles dans le code, principalement causées par l'absence de contrôles suffisants. Toutefois, ces vulnérabilités ne sont pas facilement exploitables, en raison des contraintes du protocole et de la taille relativement petite des données manipulées.

Il est important de souligner que les récepteurs DVB modernes intègrent souvent la fonctionnalité HBBTV, ce qui augmente la surface d'attaque en ajoutant un navigateur et en permettant des interactions web. Cela ouvre de nouveaux vecteurs d'exploitation potentiels. Toutefois, le produit que nous avons analysé ne supportait pas HBBTV.